├── .github └── workflows │ └── rust.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTORS.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── examples └── registry.rs └── src ├── lib.rs ├── serde_impls.rs └── transitive_impl.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | test: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | # Make sure we build without features enabled 21 | run: cargo build --verbose 22 | - name: Build 23 | run: cargo build --all-features --verbose 24 | - name: Run tests 25 | run: cargo test --all-features --verbose 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | .idea/ 4 | *.iml 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## Change Log 3 | 4 | - `pending` (0.4?,1.0?) 5 | - Added `Cow` from `MaybeOwned` implementation 6 | - Removed deprecated method (`to_mut`) 7 | - Extended impl. of `PartialOrd` to allow other 8 | right hand side types. 9 | - Feature gates transitive ops implementations 10 | (and marked them as unstable). 11 | - Transitive ops implementations now return a 12 | `MaybeOwend`/`MaybeOwnedMut` as to be more 13 | consistent with other API's and allow Things 14 | like `a + b + c`. 15 | 16 | - `v0.3.4`: 17 | - Added `make_owned()` as a `to_mut()` replacement, 18 | but also available for `MaybeOwnedMut` and more 19 | clear in it's functionality. 20 | - Added a `as_mut()` method to `MaybeOwned` which 21 | return a `Option<&mut T>` 22 | - Added missing `BorrowMut` implementation 23 | for `MaybeOwnedMut` 24 | 25 | 26 | - `v0.3.3`: 27 | - added `MaybeOwnedMut` 28 | 29 | - `v0.3.2`: 30 | - added transitive `std::ops` implementations 31 | 32 | - `v0.3.1`: 33 | - added `serde` support 34 | 35 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributors 3 | 4 | @name refers to the github nickname. 5 | 6 | Names sorted alphabetically by github nickname. 7 | Contributions ordered by PR number. 8 | 9 | ## Dabo Ross @daboross 10 | 11 | - [Add serde support](https://github.com/rustonaut/maybe-owned/pull/6) 12 | - [Update github repository links](https://github.com/rustonaut/maybe-owned/pull/7) 13 | 14 | ## Ryo Hirayama @ryo33 15 | 16 | - [Add clone_ref and clone_mut](https://github.com/rustonaut/maybe-owned/pull/12) 17 | 18 | ## Zac Burns @That3Percent 19 | 20 | - [Added MaybeOwnedMut and cleaned up along the way](https://github.com/rustonaut/maybe-owned/pull/9) 21 | 22 | ## wolfiestyle @wolfiestyle 23 | 24 | - [Extra trait implementations](https://github.com/rustonaut/maybe-owned/pull/3) 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "maybe-owned" 3 | version = "0.4.0" 4 | authors = [ 5 | "Philipp Korber ", 6 | ] 7 | description = "provides a `MaybeOwned` (and `MaybeOwnedMut`) type similar to std's `Cow` but it implements `From` and `From<&'a T>` and does not require `ToOwned`" 8 | license = "MIT OR Apache-2.0" 9 | repository = "https://github.com/rustonaut/maybe-owned" 10 | readme = "./README.md" 11 | categories = [] 12 | keywords = [ 13 | "maybe", "owned", "Cow" 14 | ] 15 | 16 | [features] 17 | unstable-transitive-ops-implementations = [] 18 | 19 | [badges] 20 | maintenance = { status = "passively-maintained" } 21 | 22 | [dependencies] 23 | serde = { version = "1", optional = true } 24 | 25 | [dev-dependencies] 26 | serde_json = "1" 27 | serde_derive = "1" 28 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Philipp Korber 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Philipp Korber 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # maybe-owned [![Crates.io](https://img.shields.io/crates/v/maybe-owned.svg)](https://crates.io/crates/maybe-owned) [![maybe-owned](https://docs.rs/maybe-owned/badge.svg)](https://docs.rs/maybe-owned) [![maintenance](https://img.shields.io/badge/maintenance-passively--maintained-blue.svg)](https://img.shields.io/badge/maintenance-passively--maintained-blue.svg) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 3 | 4 | **provides a `MaybeOwned<'a,T>` type different to std's `Cow` it implements `From` and `From<&'a T>` and does not require `ToOwned`** 5 | 6 | --- 7 | 8 | This crate provides a `MaybeOwned<'a,T>` enum. Different to `std::borrow::Cow` it 9 | implements `From` and `From<&'a T>` and does not require a `ToOwned` implementation. 10 | While this can be nice for API's mainly consuming `T`'s not implementing `ToOwned` or implementing 11 | `ToOwned` through `Clone` it also means it's borrowed version of `String` is 12 | `&String` and not `&str` making it less performant for cases like `String` or `Vec`. 13 | 14 | 15 | Documentation can be [viewed on docs.rs](https://docs.rs/maybe-owned). 16 | 17 | 18 | ## Example 19 | 20 | Take a look at the [examples dir](./examples) and the documentation 21 | for more complete examples. 22 | 23 | The main benefit of `MaybeOwned` over `Cow` is for API design, 24 | allowing API consumer to pass in both `T` and `&'a T`: 25 | 26 | ```rust 27 | 28 | //... in a trait implementation 29 | fn register(&mut self, key: SomeId, data: D) 30 | where D: Into> 31 | { 32 | self.map.entry(key).or_insert_with(||data.into()); 33 | } 34 | //... 35 | 36 | //... in usage 37 | // use owned data 38 | registry.register(id1, data_owned); 39 | // use a reference to the data 40 | registry.register(id2, &data_ref); 41 | // it ok to use the same reference again 42 | registry.register(id3, &data_ref); 43 | //... 44 | ``` 45 | 46 | ## License 47 | 48 | Licensed under either of 49 | 50 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 51 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 52 | 53 | at your option. 54 | 55 | ### Contribution 56 | 57 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. 58 | 59 | Contributors: [./CONTRIBUTORS.md](./CONTRIBUTORS.md) 60 | 61 | Change Log 62 | ----------- 63 | 64 | See [./CHANGELOG.md](./CHANGELOG.md) 65 | -------------------------------------------------------------------------------- /examples/registry.rs: -------------------------------------------------------------------------------- 1 | extern crate maybe_owned; 2 | 3 | use maybe_owned::MaybeOwned; 4 | use std::collections::HashMap; 5 | use std::time::SystemTime; 6 | 7 | struct Data { 8 | text: String, 9 | // this should be some Thing like 10 | // chrono::Date, but then it's just an examples 11 | time: SystemTime, 12 | } 13 | 14 | impl Data { 15 | fn new(text: T) -> Data 16 | where 17 | T: Into, 18 | { 19 | Data { 20 | text: text.into(), 21 | time: SystemTime::now(), 22 | } 23 | } 24 | } 25 | 26 | #[derive(Default)] 27 | struct Regestry<'a> { 28 | registry: HashMap>, 29 | } 30 | 31 | impl<'a> Regestry<'a> { 32 | fn new() -> Regestry<'a> { 33 | Default::default() 34 | } 35 | 36 | fn register_data(&mut self, key: K, data: D) -> Option> 37 | where 38 | K: Into, 39 | D: Into>, 40 | { 41 | self.registry.insert(key.into(), data.into()) 42 | } 43 | 44 | fn print_me(&self) { 45 | for (key, val) in self.registry.iter() { 46 | println!( 47 | "got: {:>6} => {:>11} {:<10} @ {:10.10?}", 48 | //we can just deref MaybeOwned 49 | key, 50 | val.text, 51 | if val.is_owned() { 52 | "[owned]" 53 | } else { 54 | "[borrowed]" 55 | }, 56 | val.time 57 | ) 58 | } 59 | } 60 | } 61 | 62 | fn main() { 63 | let shared_data = Data::new("--missing--"); 64 | 65 | let mut reg = Regestry::new(); 66 | reg.register_data("tom", Data::new("abc")); 67 | reg.register_data("lucy", &shared_data); 68 | reg.register_data("peter", &shared_data); 69 | reg.print_me(); 70 | } 71 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate only provides the `MaybeOwned` and `MaybeOwnedMut` enums 2 | //! 3 | //! Take a look at their documentation for more information. 4 | //! 5 | #![warn(missing_docs)] 6 | #[cfg(feature = "serde")] 7 | extern crate serde; 8 | 9 | #[cfg(feature = "serde")] 10 | mod serde_impls; 11 | 12 | #[cfg(feature = "unstable-transitive-ops-implementations")] 13 | mod transitive_impl; 14 | 15 | use std::borrow::{Borrow, BorrowMut, Cow}; 16 | use std::cmp::Ordering; 17 | use std::fmt; 18 | use std::hash::{Hash, Hasher}; 19 | use std::ops::{Deref, DerefMut}; 20 | use std::str::FromStr; 21 | 22 | /// This type provides a way to store data to which you either have a 23 | /// reference to or which you do own. 24 | /// 25 | /// It provides `From`, `From<&'a T>` implementations and, in difference 26 | /// to `Cow` does _not_ require `ToOwned` to be implemented which makes it 27 | /// compatible with non cloneable data, as a draw back of this it does not 28 | /// know about `ToOwned`. As a consequence of it can't know that `&str` should 29 | /// be the borrowed version of `String` and not `&String` this is especially 30 | /// bad wrt. `Box` as the borrowed version of `Box` would be `&Box`. 31 | /// 32 | /// While this crate has some drawbacks compared to `Cow` is has the benefit, 33 | /// that it works with Types which neither implement `Clone` nor `ToOwned`. 34 | /// Another benefit lies in the ability to write API functions which accept 35 | /// a generic parameter `E: Into>` as the API consumer can 36 | /// pass `T`, `&'a T` and `MaybeOwned<'a, T>` as argument, without requiring 37 | /// a explicit `Cow::Owned` or a split into two functions one accepting 38 | /// owed and the other borrowed values. 39 | /// 40 | /// # Alternatives 41 | /// 42 | /// If you mainly have values implementing `ToOwned` like `&str`/`String`, `Path`/`PathBuf` or 43 | /// `&[T]`/`Vec` using `std::borrow::Cow` might be preferable. 44 | /// 45 | /// If you want to be able to treat `&T`, `&mut T`, `Box` and `Arc` the same 46 | /// consider using [`reffers::rbma::RBMA`](https://docs.rs/reffers) 47 | /// (through not all types/platforms are supported because 48 | /// as it relies on the fact that for many pointers the lowest two bits are 0, and stores 49 | /// the discriminant in them, nevertheless this is can only be used with 32bit-aligned data, 50 | /// e.g. using a &u8 _might_ fail). RBMA also allows you to recover a `&mut T` if it was created 51 | /// from `Box`, `&mut T` or a unique `Arc`. 52 | /// 53 | /// 54 | /// # Examples 55 | /// 56 | /// ``` 57 | /// # use maybe_owned::MaybeOwned; 58 | /// struct PseudoBigData(u8); 59 | /// fn pseudo_register_fn<'a, E>(_val: E) where E: Into> { } 60 | /// 61 | /// let data = PseudoBigData(12); 62 | /// let data2 = PseudoBigData(13); 63 | /// 64 | /// pseudo_register_fn(&data); 65 | /// pseudo_register_fn(&data); 66 | /// pseudo_register_fn(data2); 67 | /// pseudo_register_fn(MaybeOwned::Owned(PseudoBigData(111))); 68 | /// ``` 69 | /// 70 | /// ``` 71 | /// # use maybe_owned::MaybeOwned; 72 | /// #[repr(C)] 73 | /// struct OpaqueFFI { 74 | /// ref1: * const u8 75 | /// //we also might want to have PhantomData etc. 76 | /// } 77 | /// 78 | /// // does not work as it does not implement `ToOwned` 79 | /// // let _ = Cow::Owned(OpaqueFFI { ref1: 0 as *const u8}); 80 | /// 81 | /// // ok, MaybeOwned can do this (but can't do &str<->String as tread of) 82 | /// let _ = MaybeOwned::Owned(OpaqueFFI { ref1: 0 as *const u8 }); 83 | /// ``` 84 | /// 85 | /// ``` 86 | /// # #[macro_use] 87 | /// # extern crate serde_derive; 88 | /// # extern crate serde_json; 89 | /// # extern crate maybe_owned; 90 | /// # #[cfg(feature = "serde")] 91 | /// # fn main() { 92 | /// # use maybe_owned::MaybeOwned; 93 | /// use std::collections::HashMap; 94 | /// 95 | /// #[derive(Serialize, Deserialize)] 96 | /// struct SerializedData<'a> { 97 | /// data: MaybeOwned<'a, HashMap>, 98 | /// } 99 | /// 100 | /// let mut map = HashMap::new(); 101 | /// map.insert("answer".to_owned(), 42); 102 | /// 103 | /// // serializing can use borrowed data to avoid unnecessary copying 104 | /// let bytes = serde_json::to_vec(&SerializedData { data: (&map).into() }).unwrap(); 105 | /// 106 | /// // deserializing creates owned data 107 | /// let deserialized: SerializedData = serde_json::from_slice(&bytes).unwrap(); 108 | /// assert_eq!(deserialized.data["answer"], 42); 109 | /// # } 110 | /// # #[cfg(not(feature = "serde"))] fn main() {} 111 | /// ``` 112 | /// 113 | /// # Transitive `std::ops` implementations 114 | /// 115 | /// There are transitive implementations for most operator in `std::ops`. 116 | /// 117 | /// A Op between a `MaybeOwned` and `MaybeOwned` is implemented if: 118 | /// 119 | /// - L impl the Op with R 120 | /// - L impl the Op with &R 121 | /// - &L impl the Op with R 122 | /// - &L impl the Op with &R 123 | /// - the `Output` of all aboves implementations is 124 | /// the same type 125 | /// 126 | /// 127 | /// The `Neg` (`-` prefix) op is implemented for `V` if: 128 | /// 129 | /// - `V` impl `Neg` 130 | /// - `&V` impl `Neg` 131 | /// - both have the same `Output` 132 | /// 133 | /// 134 | /// The `Not` (`!` prefix) op is implemented for `V` if: 135 | /// 136 | /// - `V` impl `Not` 137 | /// - `&V` impl `Not` 138 | /// - both have the same `Output` 139 | /// 140 | /// Adding implementations for Ops which add a `MaybeOwned` to 141 | /// a non `MaybeOwned` value (like `MaybeOwned + T`) requires 142 | /// far reaching specialization in rust and is therefore not done 143 | /// for now. 144 | #[derive(Debug)] 145 | pub enum MaybeOwned<'a, T: 'a> { 146 | /// owns T 147 | Owned(T), 148 | /// has a reference to T 149 | Borrowed(&'a T), 150 | } 151 | 152 | /// This type is basically the same as `MaybeOwned`, 153 | /// but works with mutable references. 154 | /// 155 | /// Note that while you can se `MaybeOwned` as a alternative 156 | /// implementation for a Cow (Copy-On-Write) type this isn't 157 | /// really the case for `MaybeOwnedMut` as changing it will 158 | /// potentially change the source through the given `&mut` 159 | /// reference. For example the transitive add assign (+=) 160 | /// implementation for `MaybeOwned` does (need to) convert 161 | /// the given instance into a owned variant before using 162 | /// `+=` on the contained type. But for `MaybeOwnedMut` it 163 | /// can directly use `+=` on the `&mut` contained in the 164 | /// `Borrowed` variant! 165 | #[derive(Debug)] 166 | pub enum MaybeOwnedMut<'a, T: 'a> { 167 | /// owns T 168 | Owned(T), 169 | /// has a reference to T 170 | Borrowed(&'a mut T), 171 | } 172 | 173 | macro_rules! common_impls { 174 | ($Name:ident) => { 175 | impl $Name<'_, T> { 176 | /// Returns true if the data is owned else false. 177 | pub fn is_owned(&self) -> bool { 178 | match self { 179 | Self::Owned(_) => true, 180 | Self::Borrowed(_) => false, 181 | } 182 | } 183 | 184 | /// Returns a new `MaybeOwned::Borrowed` without cloning the data. 185 | pub fn to_ref(&self) -> MaybeOwned<'_, T> { 186 | match self { 187 | Self::Owned(v) => MaybeOwned::Borrowed(v), 188 | Self::Borrowed(v) => MaybeOwned::Borrowed(v), 189 | } 190 | } 191 | } 192 | 193 | impl $Name<'_, T> { 194 | /// Return the contained data in it's owned form. 195 | /// 196 | /// If it's borrowed this will clone it. 197 | pub fn into_owned(self) -> T { 198 | match self { 199 | Self::Owned(v) => v, 200 | Self::Borrowed(v) => v.clone(), 201 | } 202 | } 203 | 204 | /// Internally converts the type into it's owned variant. 205 | /// 206 | /// Conversion from a reference to the owned variant is done by cloning. 207 | /// 208 | /// *This returns a `&mut T` and as such can be used to "unconditionally" 209 | /// get an `&mut T`*. Be aware that while this works with both `MaybeOwned` 210 | /// and `MaybeOwnedMut` it also converts it to an owned variant in both 211 | /// cases. So while it's the best way to get a `&mut T` for `MaybeOwned` 212 | /// for `MaybeOwnedMut` it's preferable to use `as_mut` from `AsMut`. 213 | /// 214 | /// ## Example 215 | /// 216 | /// ``` 217 | /// use maybe_owned::MaybeOwned; 218 | /// 219 | /// #[derive(Clone, Debug, PartialEq, Eq)] 220 | /// struct PseudoBigData(u8); 221 | /// 222 | /// let data = PseudoBigData(12); 223 | /// 224 | /// let mut maybe: MaybeOwned = (&data).into(); 225 | /// assert_eq!(false, maybe.is_owned()); 226 | /// 227 | /// { 228 | /// let reference = maybe.make_owned(); 229 | /// assert_eq!(&mut PseudoBigData(12), reference); 230 | /// } 231 | /// assert!(maybe.is_owned()); 232 | /// ``` 233 | pub fn make_owned(&mut self) -> &mut T { 234 | match self { 235 | Self::Owned(v) => v, 236 | Self::Borrowed(v) => { 237 | *self = Self::Owned(v.clone()); 238 | match self { 239 | Self::Owned(v) => v, 240 | Self::Borrowed(..) => unreachable!(), 241 | } 242 | } 243 | } 244 | } 245 | } 246 | 247 | impl Deref for $Name<'_, T> { 248 | type Target = T; 249 | 250 | fn deref(&self) -> &T { 251 | match self { 252 | Self::Owned(v) => v, 253 | Self::Borrowed(v) => v, 254 | } 255 | } 256 | } 257 | 258 | impl AsRef for $Name<'_, T> { 259 | fn as_ref(&self) -> &T { 260 | self 261 | } 262 | } 263 | 264 | impl From for $Name<'_, T> { 265 | fn from(v: T) -> Self { 266 | Self::Owned(v) 267 | } 268 | } 269 | 270 | impl Borrow for $Name<'_, T> { 271 | fn borrow(&self) -> &T { 272 | self 273 | } 274 | } 275 | 276 | impl Default for $Name<'_, T> { 277 | fn default() -> Self { 278 | Self::Owned(T::default()) 279 | } 280 | } 281 | 282 | impl<'b, A: PartialEq, B> PartialEq<$Name<'b, B>> for $Name<'_, A> { 283 | #[inline] 284 | fn eq(&self, other: &$Name<'b, B>) -> bool { 285 | PartialEq::eq(self.deref(), other.deref()) 286 | } 287 | } 288 | 289 | impl<'a, T: Eq> Eq for $Name<'a, T> {} 290 | 291 | impl FromStr for $Name<'_, T> { 292 | type Err = T::Err; 293 | 294 | fn from_str(s: &str) -> Result { 295 | Ok(Self::Owned(T::from_str(s)?)) 296 | } 297 | } 298 | 299 | impl<'b, A: PartialOrd, B> PartialOrd<$Name<'b, B>> for $Name<'_, A> { 300 | #[inline] 301 | fn partial_cmp(&self, other: &$Name<'b, B>) -> Option { 302 | PartialOrd::partial_cmp(self.deref(), other.deref()) 303 | } 304 | } 305 | 306 | impl Ord for $Name<'_, T> { 307 | #[inline] 308 | fn cmp(&self, other: &Self) -> Ordering { 309 | Ord::cmp(self.deref(), other.deref()) 310 | } 311 | } 312 | 313 | impl Hash for $Name<'_, T> { 314 | #[inline] 315 | fn hash(&self, state: &mut H) { 316 | Hash::hash(self.deref(), state) 317 | } 318 | } 319 | 320 | impl<'a, T: fmt::Display> fmt::Display for $Name<'a, T> { 321 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 322 | match self { 323 | Self::Owned(o) => fmt::Display::fmt(o, f), 324 | Self::Borrowed(b) => fmt::Display::fmt(b, f), 325 | } 326 | } 327 | } 328 | }; 329 | } 330 | 331 | common_impls!(MaybeOwned); 332 | common_impls!(MaybeOwnedMut); 333 | 334 | impl<'a, T> From<&'a T> for MaybeOwned<'a, T> { 335 | fn from(v: &'a T) -> Self { 336 | Self::Borrowed(v) 337 | } 338 | } 339 | 340 | impl<'a, T> From<&'a mut T> for MaybeOwnedMut<'a, T> { 341 | fn from(v: &'a mut T) -> Self { 342 | Self::Borrowed(v) 343 | } 344 | } 345 | 346 | impl<'a, T: ToOwned> From> for MaybeOwned<'a, T> { 347 | fn from(cow: Cow<'a, T>) -> MaybeOwned<'a, T> { 348 | match cow { 349 | Cow::Owned(v) => MaybeOwned::Owned(v), 350 | Cow::Borrowed(v) => MaybeOwned::Borrowed(v), 351 | } 352 | } 353 | } 354 | 355 | impl<'a, T: ToOwned> From> for Cow<'a, T> { 356 | fn from(container: MaybeOwned<'a, T>) -> Cow<'a, T> { 357 | match container { 358 | MaybeOwned::Owned(v) => Cow::Owned(v), 359 | MaybeOwned::Borrowed(v) => Cow::Borrowed(v), 360 | } 361 | } 362 | } 363 | 364 | impl Clone for MaybeOwned<'_, T> { 365 | fn clone(&self) -> Self { 366 | match self { 367 | Self::Owned(v) => Self::Owned(v.clone()), 368 | Self::Borrowed(v) => Self::Borrowed(v), 369 | } 370 | } 371 | } 372 | 373 | impl MaybeOwned<'_, T> { 374 | /// Returns a `&mut` if possible. 375 | /// 376 | /// If the internal representation is borrowed (`&T`) then 377 | /// this method will return `None` 378 | pub fn as_mut(&mut self) -> Option<&mut T> { 379 | match self { 380 | MaybeOwned::Owned(value) => Some(value), 381 | MaybeOwned::Borrowed(_) => None, 382 | } 383 | } 384 | } 385 | 386 | impl DerefMut for MaybeOwnedMut<'_, T> { 387 | fn deref_mut(&mut self) -> &mut T { 388 | match self { 389 | Self::Owned(v) => v, 390 | Self::Borrowed(v) => v, 391 | } 392 | } 393 | } 394 | 395 | impl AsMut for MaybeOwnedMut<'_, T> { 396 | fn as_mut(&mut self) -> &mut T { 397 | match self { 398 | Self::Owned(v) => v, 399 | Self::Borrowed(v) => v, 400 | } 401 | } 402 | } 403 | 404 | impl BorrowMut for MaybeOwnedMut<'_, T> { 405 | fn borrow_mut(&mut self) -> &mut T { 406 | self 407 | } 408 | } 409 | 410 | impl MaybeOwnedMut<'_, T> { 411 | /// Returns a new `MaybeOwnedMut::Borrowed` without cloning the data. 412 | pub fn to_mut(&mut self) -> MaybeOwnedMut<'_, T> { 413 | match self { 414 | Self::Owned(v) => MaybeOwnedMut::Borrowed(v), 415 | Self::Borrowed(v) => MaybeOwnedMut::Borrowed(v), 416 | } 417 | } 418 | } 419 | 420 | #[cfg(test)] 421 | mod tests { 422 | use super::*; 423 | 424 | type TestType = Vec<()>; 425 | 426 | fn with_into<'a, I: Into>>(v: I) -> MaybeOwned<'a, TestType> { 427 | v.into() 428 | } 429 | 430 | #[test] 431 | fn is_owned() { 432 | let data = TestType::default(); 433 | assert!(MaybeOwned::Owned(data).is_owned()); 434 | } 435 | 436 | #[test] 437 | fn make_owned() { 438 | let mut a = MaybeOwned::Borrowed(&12u8); 439 | assert!(!a.is_owned()); 440 | a.make_owned(); 441 | assert!(a.is_owned()); 442 | assert_eq!(&*a, &12); 443 | } 444 | 445 | #[test] 446 | fn into_with_owned() { 447 | //ty check if it accepts references 448 | let data = TestType::default(); 449 | assert!(with_into(data).is_owned()) 450 | } 451 | #[test] 452 | fn into_with_borrow() { 453 | //ty check if it accepts references 454 | let data = TestType::default(); 455 | assert!(!with_into(&data).is_owned()); 456 | } 457 | 458 | #[test] 459 | fn clone_owned() { 460 | let maybe = MaybeOwned::::default(); 461 | assert!(maybe.clone().is_owned()); 462 | } 463 | 464 | #[test] 465 | fn clone_borrow() { 466 | let data = TestType::default(); 467 | let maybe: MaybeOwned = (&data).into(); 468 | assert!(!maybe.clone().is_owned()); 469 | } 470 | 471 | #[test] 472 | fn into_inner() { 473 | let data = vec![1u32, 2]; 474 | let maybe: MaybeOwned> = (&data).into(); 475 | assert_eq!(data, maybe.into_owned()); 476 | } 477 | 478 | #[test] 479 | fn has_default() { 480 | #[derive(Default)] 481 | struct TestType(u8); 482 | let _x: MaybeOwned = Default::default(); 483 | } 484 | 485 | #[test] 486 | fn has_clone() { 487 | #[derive(Clone)] 488 | struct TestType(u8); 489 | let _x = TestType(12).clone(); 490 | } 491 | 492 | #[test] 493 | fn has_deref() { 494 | let a = MaybeOwned::Owned(vec![1u8]); 495 | let _ = a.len(); 496 | 497 | let a = MaybeOwnedMut::Owned(vec![1u8]); 498 | let _ = a.len(); 499 | } 500 | 501 | #[test] 502 | fn has_deref_mut() { 503 | let mut a = MaybeOwnedMut::Owned(vec![1u8]); 504 | a[0] = 12u8; 505 | } 506 | 507 | #[test] 508 | fn has_partial_eq() { 509 | #[derive(PartialEq)] 510 | struct TestType(f32); 511 | 512 | let n = TestType(33.0); 513 | let a = MaybeOwned::Owned(TestType(42.0)); 514 | let b = MaybeOwned::Borrowed(&n); 515 | let c = MaybeOwned::Owned(TestType(33.0)); 516 | 517 | assert_eq!(a == b, false); 518 | assert_eq!(b == c, true); 519 | assert_eq!(c == a, false); 520 | } 521 | 522 | #[test] 523 | fn has_eq() { 524 | #[derive(PartialEq, Eq)] 525 | struct TestType(i32); 526 | 527 | let n = TestType(33); 528 | let a = MaybeOwned::Owned(TestType(42)); 529 | let b = MaybeOwned::Borrowed(&n); 530 | let c = MaybeOwned::Owned(TestType(33)); 531 | 532 | assert_eq!(a == b, false); 533 | assert_eq!(b == c, true); 534 | assert_eq!(c == a, false); 535 | } 536 | 537 | #[test] 538 | fn has_partial_ord() { 539 | #[derive(PartialEq, PartialOrd)] 540 | struct TestType(f32); 541 | 542 | let n = TestType(33.0); 543 | let a = MaybeOwned::Owned(TestType(42.0)); 544 | let b = MaybeOwned::Borrowed(&n); 545 | let c = MaybeOwned::Owned(TestType(33.0)); 546 | 547 | assert_eq!(a > b, true); 548 | assert_eq!(b > c, false); 549 | assert_eq!(a < c, false); 550 | } 551 | 552 | #[test] 553 | fn has_ord() { 554 | #[derive(PartialEq, Eq, PartialOrd, Ord)] 555 | struct TestType(i32); 556 | 557 | let n = TestType(33); 558 | let a = MaybeOwned::Owned(TestType(42)); 559 | let b = MaybeOwned::Borrowed(&n); 560 | let c = MaybeOwned::Owned(TestType(33)); 561 | 562 | assert_eq!(a > b, true); 563 | assert_eq!(b > c, false); 564 | assert_eq!(a < c, false); 565 | } 566 | 567 | #[test] 568 | fn has_hash() { 569 | use std::collections::HashMap; 570 | 571 | let mut map = HashMap::new(); 572 | map.insert(MaybeOwned::Owned(42), 33); 573 | 574 | assert_eq!(map.get(&MaybeOwned::Borrowed(&42)), Some(&33)); 575 | } 576 | 577 | #[test] 578 | fn has_borrow() { 579 | let v = MaybeOwned::Owned(42); 580 | let _ = Borrow::::borrow(&v); 581 | 582 | let v = MaybeOwnedMut::Owned(42); 583 | let _ = Borrow::::borrow(&v); 584 | } 585 | 586 | #[test] 587 | fn has_borrow_mut() { 588 | let mut v = MaybeOwnedMut::Owned(42); 589 | let _ = BorrowMut::::borrow_mut(&mut v); 590 | } 591 | 592 | #[test] 593 | fn has_as_ref() { 594 | let v: MaybeOwned = 42.into(); 595 | let _: &u8 = v.as_ref(); 596 | 597 | let v: MaybeOwnedMut = 42.into(); 598 | let _: &u8 = v.as_ref(); 599 | } 600 | 601 | #[test] 602 | fn has_as_mut() { 603 | // uses a as_mut method 604 | let mut v: MaybeOwned = (&11).into(); 605 | assert_eq!(v.as_mut(), None); 606 | 607 | let mut v: MaybeOwned = 12.into(); 608 | assert_eq!(v.as_mut(), Some(&mut 12)); 609 | 610 | // uses AsMut 611 | let mut v = MaybeOwnedMut::Owned(42); 612 | let _: &mut u8 = v.as_mut(); 613 | } 614 | 615 | #[test] 616 | fn has_display() { 617 | let n = 33; 618 | let a = MaybeOwned::Owned(42); 619 | let b = MaybeOwned::Borrowed(&n); 620 | 621 | let s = format!("{} {}", a, b); 622 | 623 | assert_eq!(s, "42 33"); 624 | } 625 | 626 | #[test] 627 | fn from_cow() { 628 | use std::borrow::Cow; 629 | 630 | fn test<'a, V: Into>>(v: V, n: i32) { 631 | assert_eq!(*v.into(), n) 632 | } 633 | 634 | let n = 33; 635 | test(Cow::Owned(42), 42); 636 | test(Cow::Borrowed(&n), n); 637 | } 638 | 639 | #[test] 640 | fn into_cow() { 641 | use std::borrow::Cow; 642 | 643 | fn test<'a, V: Into>>(v: V, n: i32) { 644 | assert_eq!(*v.into(), n) 645 | } 646 | 647 | let n = 33; 648 | test(MaybeOwned::Owned(42), 42); 649 | test(MaybeOwned::Borrowed(&n), n); 650 | } 651 | 652 | #[test] 653 | fn from_str() { 654 | let as_string = "12"; 655 | //assumption as_string is convertable to u32 656 | assert_eq!(12u32, as_string.parse().unwrap()); 657 | assert_eq!(MaybeOwned::Owned(12u32), as_string.parse().unwrap()); 658 | } 659 | 660 | #[test] 661 | fn as_ref() { 662 | let data = TestType::default(); 663 | let maybe_owned = MaybeOwned::Borrowed(&data); 664 | let _ref: &TestType = maybe_owned.as_ref(); 665 | assert_eq!(&data as *const _ as usize, _ref as *const _ as usize); 666 | } 667 | 668 | #[test] 669 | fn borrow() { 670 | use std::borrow::Borrow; 671 | 672 | let data = TestType::default(); 673 | let maybe_owned = MaybeOwned::Borrowed(&data); 674 | let _ref: &TestType = maybe_owned.borrow(); 675 | assert_eq!(&data as *const _ as usize, _ref as *const _ as usize); 676 | } 677 | 678 | #[test] 679 | fn reborrow_mut() { 680 | let value = vec![0u32]; 681 | let mut value = MaybeOwnedMut::Owned(value); 682 | let mut reborrow = MaybeOwnedMut::Borrowed(value.deref_mut()); 683 | reborrow.push(1); 684 | assert_eq!(&[0, 1], &value[..]); 685 | } 686 | 687 | #[test] 688 | fn to_ref_borrowed() { 689 | let data = TestType::default(); 690 | let maybe_owned = MaybeOwned::Borrowed(&data); 691 | let referenced = maybe_owned.to_ref(); 692 | assert_eq!(maybe_owned, referenced); 693 | assert!(!referenced.is_owned()); 694 | } 695 | 696 | #[test] 697 | fn to_ref_owned() { 698 | let maybe_owned = MaybeOwned::Owned(TestType::default()); 699 | let referenced = maybe_owned.to_ref(); 700 | assert_eq!(maybe_owned, referenced); 701 | assert!(!referenced.is_owned()); 702 | } 703 | 704 | #[test] 705 | fn clone_mut_borrowed() { 706 | let mut data = TestType::default(); 707 | let mut maybe_owned = MaybeOwnedMut::Borrowed(&mut data); 708 | let mut referenced = maybe_owned.to_mut(); 709 | assert_eq!(referenced.deref_mut(), &mut TestType::default()); 710 | assert!(!referenced.is_owned()); 711 | } 712 | 713 | #[test] 714 | fn clone_mut_owned() { 715 | let mut maybe_owned = MaybeOwnedMut::Owned(TestType::default()); 716 | let mut cloned = maybe_owned.to_mut(); 717 | assert_eq!(cloned.deref_mut(), &mut TestType::default()); 718 | assert!(!cloned.is_owned()); 719 | } 720 | } 721 | -------------------------------------------------------------------------------- /src/serde_impls.rs: -------------------------------------------------------------------------------- 1 | //! Serde `Serialize` and `Deserialize` implementations for `MaybeOwned`. 2 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 3 | 4 | use {MaybeOwned, MaybeOwnedMut}; 5 | 6 | macro_rules! serde_impls { 7 | ($Name:ident) => { 8 | impl<'a, T: Serialize> Serialize for $Name<'a, T> { 9 | fn serialize(&self, serializer: S) -> Result { 10 | match self { 11 | Self::Owned(v) => v.serialize(serializer), 12 | Self::Borrowed(v) => v.serialize(serializer), 13 | } 14 | } 15 | } 16 | 17 | impl<'a, 'de, T: Deserialize<'de>> Deserialize<'de> for $Name<'a, T> { 18 | fn deserialize(deserializer: D) -> Result 19 | where 20 | D: Deserializer<'de>, 21 | { 22 | T::deserialize(deserializer).map(Self::Owned) 23 | } 24 | } 25 | }; 26 | } 27 | 28 | serde_impls!(MaybeOwned); 29 | serde_impls!(MaybeOwnedMut); 30 | -------------------------------------------------------------------------------- /src/transitive_impl.rs: -------------------------------------------------------------------------------- 1 | use std::ops::*; 2 | 3 | use super::{MaybeOwned, MaybeOwnedMut}; 4 | 5 | macro_rules! impl_op { 6 | ($([$OP:ident : $op:ident, $OP_ASSIGN:ident : $op_assign: ident]),*) => ($( 7 | impl<'min, L, R, OUT: 'min> $OP> for MaybeOwned<'min, L> 8 | where L: $OP + $OP<&'min R, Output=OUT>, 9 | &'min L: $OP + $OP<&'min R, Output=OUT> 10 | { 11 | type Output = MaybeOwned<'min, OUT>; 12 | 13 | fn $op(self, rhs: MaybeOwned<'min, R>) -> Self::Output { 14 | use self::MaybeOwned::*; 15 | let result = match (self, rhs) { 16 | (Owned(l), Owned(r)) => l.$op(r), 17 | (Owned(l), Borrowed(r)) => l.$op(r), 18 | (Borrowed(l), Owned(r)) => l.$op(r), 19 | (Borrowed(l), Borrowed(r)) => l.$op(r) 20 | }; 21 | Owned(result) 22 | } 23 | } 24 | 25 | // Note: With an additional macro level we could fold this with the 26 | // previous $OP implementation. But the additional read complexity 27 | // isn't really worth it. 28 | impl<'min, L, R, OUT: 'min> $OP> for MaybeOwnedMut<'min, L> 29 | where L: $OP + $OP<&'min R, Output=OUT>, 30 | &'min L: $OP + $OP<&'min R, Output=OUT> 31 | { 32 | type Output = MaybeOwnedMut<'min, OUT>; 33 | 34 | fn $op(self, rhs: MaybeOwnedMut<'min, R>) -> Self::Output { 35 | use self::MaybeOwnedMut::*; 36 | let result = match (self, rhs) { 37 | (Owned(l), Owned(r)) => l.$op(r), 38 | (Owned(l), Borrowed(r)) => l.$op(&*r), 39 | (Borrowed(l), Owned(r)) => (&*l).$op(r), 40 | (Borrowed(l), Borrowed(r)) => (&*l).$op(&*r) 41 | }; 42 | Owned(result) 43 | } 44 | } 45 | 46 | impl<'min, L, R> $OP_ASSIGN> for MaybeOwned<'min, L> 47 | where L: Clone + $OP_ASSIGN + $OP_ASSIGN<&'min R> 48 | { 49 | 50 | fn $op_assign(&mut self, rhs: MaybeOwned<'min, R>) { 51 | use self::MaybeOwned::*; 52 | match rhs { 53 | Owned(r) => self.make_owned().$op_assign(r), 54 | Borrowed(r) => self.make_owned().$op_assign(r) 55 | } 56 | } 57 | } 58 | 59 | impl<'min, L, R> $OP_ASSIGN> for MaybeOwnedMut<'min, L> 60 | where L: $OP_ASSIGN + $OP_ASSIGN<&'min R> 61 | { 62 | 63 | fn $op_assign(&mut self, rhs: MaybeOwnedMut<'min, R>) { 64 | use self::MaybeOwnedMut::*; 65 | match rhs { 66 | Owned(r) => self.as_mut().$op_assign(r), 67 | Borrowed(r) => self.as_mut().$op_assign(&*r) 68 | } 69 | } 70 | } 71 | )*); 72 | } 73 | 74 | impl_op! { 75 | [Add: add, AddAssign: add_assign], 76 | [Sub: sub, SubAssign: sub_assign], 77 | [Mul: mul, MulAssign: mul_assign], 78 | [Div: div, DivAssign: div_assign], 79 | [Shl: shl, ShlAssign: shl_assign], 80 | [Shr: shr, ShrAssign: shr_assign], 81 | [BitAnd: bitand, BitAndAssign: bitand_assign], 82 | [BitOr: bitor, BitOrAssign: bitor_assign ], 83 | [BitXor: bitxor, BitXorAssign: bitxor_assign] 84 | } 85 | 86 | impl<'l, V, OUT> Neg for MaybeOwned<'l, V> 87 | where 88 | V: Neg, 89 | &'l V: Neg, 90 | { 91 | type Output = OUT; 92 | 93 | //TODO this should return a MaybeOwned 94 | fn neg(self) -> Self::Output { 95 | use self::MaybeOwned::*; 96 | 97 | match self { 98 | Owned(s) => s.neg(), 99 | Borrowed(s) => s.neg(), 100 | } 101 | } 102 | } 103 | 104 | impl<'l, V, OUT> Neg for MaybeOwnedMut<'l, V> 105 | where 106 | V: Neg, 107 | &'l V: Neg, 108 | { 109 | type Output = OUT; 110 | 111 | //TODO this should return a MaybeOwned 112 | fn neg(self) -> Self::Output { 113 | use self::MaybeOwnedMut::*; 114 | 115 | match self { 116 | Owned(s) => s.neg(), 117 | Borrowed(s) => (&*s).neg(), 118 | } 119 | } 120 | } 121 | 122 | impl<'l, V, OUT> Not for MaybeOwned<'l, V> 123 | where 124 | V: Not, 125 | &'l V: Not, 126 | { 127 | type Output = V::Output; 128 | 129 | //TODO this should return a MaybeOwned 130 | fn not(self) -> Self::Output { 131 | use self::MaybeOwned::*; 132 | 133 | match self { 134 | Owned(s) => s.not(), 135 | Borrowed(s) => s.not(), 136 | } 137 | } 138 | } 139 | 140 | impl<'l, V, OUT> Not for MaybeOwnedMut<'l, V> 141 | where 142 | V: Not, 143 | &'l V: Not, 144 | { 145 | type Output = V::Output; 146 | 147 | //TODO this should return a MaybeOwned 148 | fn not(self) -> Self::Output { 149 | use self::MaybeOwnedMut::*; 150 | 151 | match self { 152 | Owned(s) => s.not(), 153 | Borrowed(s) => (&*s).not(), 154 | } 155 | } 156 | } 157 | 158 | #[cfg(test)] 159 | mod test { 160 | use super::*; 161 | use std::ops::{Add, AddAssign, Neg, Not}; 162 | 163 | //FIXME the test might need some cleanup. 164 | 165 | #[derive(Clone, PartialEq)] 166 | struct Thing { 167 | x: u8, 168 | } 169 | 170 | impl Add for Thing { 171 | type Output = u8; 172 | 173 | fn add(self, rhs: Thing) -> Self::Output { 174 | self.x + rhs.x 175 | } 176 | } 177 | impl AddAssign for Thing { 178 | fn add_assign(&mut self, rhs: Thing) { 179 | self.x += rhs.x 180 | } 181 | } 182 | impl<'a> Add<&'a Thing> for Thing { 183 | type Output = u8; 184 | 185 | fn add(self, rhs: &'a Thing) -> Self::Output { 186 | self.x + rhs.x 187 | } 188 | } 189 | impl<'a> AddAssign<&'a Thing> for Thing { 190 | fn add_assign(&mut self, rhs: &'a Thing) { 191 | self.x += rhs.x 192 | } 193 | } 194 | impl<'a> Add for &'a Thing { 195 | type Output = u8; 196 | 197 | fn add(self, rhs: Thing) -> Self::Output { 198 | self.x + rhs.x 199 | } 200 | } 201 | impl<'a, 'b> Add<&'a Thing> for &'b Thing { 202 | type Output = u8; 203 | 204 | fn add(self, rhs: &'a Thing) -> Self::Output { 205 | self.x + rhs.x 206 | } 207 | } 208 | 209 | impl Not for Thing { 210 | type Output = bool; 211 | 212 | fn not(self) -> Self::Output { 213 | self.x != 0 214 | } 215 | } 216 | 217 | impl<'a> Not for &'a Thing { 218 | type Output = bool; 219 | 220 | fn not(self) -> Self::Output { 221 | self.x != 0 222 | } 223 | } 224 | 225 | impl Neg for Thing { 226 | type Output = i8; 227 | 228 | fn neg(self) -> Self::Output { 229 | -(self.x as i8) 230 | } 231 | } 232 | 233 | impl<'a> Neg for &'a Thing { 234 | type Output = i8; 235 | 236 | fn neg(self) -> Self::Output { 237 | -(self.x as i8) 238 | } 239 | } 240 | 241 | #[test] 242 | fn op_impls_exist() { 243 | let a = MaybeOwned::from(Thing { x: 12 }); 244 | let b = MaybeOwned::from(Thing { x: 13 }); 245 | assert_eq!(a + b, MaybeOwned::Owned(25u8)); 246 | 247 | let c = Thing { x: 42 }; 248 | let c1: MaybeOwned = (&c).into(); 249 | let c2: MaybeOwned = (&c).into(); 250 | 251 | assert_eq!(c1 + c2, MaybeOwned::Owned(84)); 252 | } 253 | 254 | #[test] 255 | fn op_impls_exist_for_mut() { 256 | let a: MaybeOwnedMut = Thing { x: 12 }.into(); 257 | let b: MaybeOwnedMut = Thing { x: 13 }.into(); 258 | assert_eq!(a + b, MaybeOwnedMut::Owned(25)); 259 | 260 | let mut c0a = Thing { x: 42 }; 261 | let mut c0b = Thing { x: 8 }; 262 | let c1: MaybeOwnedMut = (&mut c0a).into(); 263 | let c2: MaybeOwnedMut = (&mut c0b).into(); 264 | assert_eq!(c1 + c2, MaybeOwnedMut::Owned(50)); 265 | } 266 | 267 | #[test] 268 | fn op_assign_impls_exist() { 269 | let mut a = MaybeOwned::from(Thing { x: 2 }); 270 | a += MaybeOwned::from(Thing { x: 3 }); 271 | assert_eq!(a.x, 5); 272 | 273 | let a = Thing { x: 2 }; 274 | let mut a: MaybeOwned = (&a).into(); 275 | assert!(!a.is_owned()); 276 | a += MaybeOwned::from(Thing { x: 5 }); 277 | assert!(a.is_owned()); 278 | assert_eq!(a.as_ref().x, 7); 279 | } 280 | 281 | #[test] 282 | fn op_assign_impls_exist_mut() { 283 | let mut a: MaybeOwnedMut = Thing { x: 2 }.into(); 284 | a += MaybeOwnedMut::from(Thing { x: 3 }); 285 | assert_eq!(a.x, 5); 286 | 287 | let mut a = Thing { x: 2 }; 288 | let mut a: MaybeOwnedMut = (&mut a).into(); 289 | assert!(!a.is_owned()); 290 | a += MaybeOwnedMut::from(Thing { x: 5 }); 291 | assert!(!a.is_owned()); 292 | assert_eq!(a.as_ref().x, 7); 293 | } 294 | 295 | #[test] 296 | fn not_and_neg_work_for_thing_test_type() { 297 | assert_eq!(!Thing { x: 0 }, false); 298 | assert_eq!(!Thing { x: 1 }, true); 299 | assert_eq!(!&Thing { x: 0 }, false); 300 | assert_eq!(!&Thing { x: 1 }, true); 301 | } 302 | 303 | #[test] 304 | fn not_and_neg_are_impl() { 305 | let a = Thing { x: 5 }; 306 | let a1: MaybeOwned = (&a).into(); 307 | let a2: MaybeOwned = (&a).into(); 308 | assert_eq!(!a1, true); 309 | assert_eq!(-a2, -5i8); 310 | } 311 | 312 | #[test] 313 | fn not_and_neg_are_impl_mut() { 314 | let mut a = Thing { x: 5 }; 315 | let mut b = Thing { x: 0 }; 316 | let a1: MaybeOwnedMut = (&mut a).into(); 317 | let b1: MaybeOwnedMut = (&mut b).into(); 318 | 319 | assert_eq!(!a1, true); 320 | assert_eq!(!b1, false); 321 | 322 | let a2: MaybeOwnedMut = (&mut a).into(); 323 | assert_eq!(-a2, -5i8); 324 | } 325 | } 326 | --------------------------------------------------------------------------------