├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── example ├── Cargo.toml └── src │ └── main.rs ├── reborrow-derive ├── Cargo.toml ├── LICENSE └── src │ └── lib.rs └── reborrow ├── Cargo.toml ├── LICENSE └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "reborrow", 4 | "reborrow-derive", 5 | "example", 6 | ] 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 sarah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Emulate reborrowing for user types. 2 | 3 | A generalized reference is a type that has reference semantics, without actually being 4 | a native Rust reference (like `&T` and `&mut T`). e.g.: 5 | 6 | ```rust 7 | struct MyRefMut<'borrow> { 8 | a: &'borrow mut i32, 9 | b: &'borrow mut i32, 10 | } 11 | ``` 12 | 13 | Given a `&'a` \[mut\] reference of a `&'b` view over some owned object, 14 | reborrowing it means getting an active `&'a` view over the owned object, 15 | which renders the original reference inactive until it's dropped, at which point 16 | the original reference becomes active again. 17 | 18 | This crate defines traits to make generalized references more ergonomic to use by giving the 19 | ability to borrow and reborrow them. 20 | 21 | # Features 22 | 23 | `derive`: This imports a derive macro helper for implementing reborrow for user 24 | types. It can be used with a `Ref/RefMut` pair of structs/tuple structs with 25 | the same member names, one containing shared references and the other mutable 26 | references. The shared variant must be `Copy`, and the macro is used on the 27 | mutable variant and generates the relevant traits for both types. 28 | 29 | # Examples 30 | 31 | This fails to compile since we can't use a non-`Copy` value after it's moved. 32 | 33 | ```rust 34 | fn takes_mut_option(o: Option<&mut i32>) {} 35 | 36 | let mut x = 0; 37 | let o = Some(&mut x); 38 | takes_mut_option(o); // `o` is moved here, 39 | takes_mut_option(o); // so it can't be used here. 40 | ``` 41 | 42 | This can be worked around by unwrapping the option, reborrowing it, and then wrapping it again. 43 | 44 | ```rust 45 | fn takes_mut_option(o: Option<&mut i32>) {} 46 | 47 | let mut x = 0; 48 | let mut o = Some(&mut x); 49 | takes_mut_option(o.as_mut().map(|r| &mut **r)); // "Reborrowing" the `Option` 50 | takes_mut_option(o.as_mut().map(|r| &mut **r)); // allows us to use it later on. 51 | drop(o); // can still be used here 52 | ``` 53 | 54 | Using this crate, this can be shortened to 55 | 56 | ```rust 57 | use reborrow::ReborrowMut; 58 | 59 | fn takes_mut_option(o: Option<&mut i32>) {} 60 | 61 | let mut x = 0; 62 | let mut o = Some(&mut x); 63 | takes_mut_option(o.rb_mut()); // "Reborrowing" the `Option` 64 | takes_mut_option(o.rb_mut()); // allows us to use it later on. 65 | drop(o); // can still be used here 66 | ``` 67 | 68 | The derive macro can be used with structs or tuple structs, and generates 69 | the trait definitions for `Reborrow` and `ReborrowMut`. 70 | 71 | ```rust 72 | use reborrow::{ReborrowCopyTraits, ReborrowTraits}; 73 | 74 | #[derive(ReborrowCopyTraits)] 75 | pub struct I32Ref<'a, 'b> { 76 | pub i: i32, 77 | pub j: &'a i32, 78 | pub k: &'b i32, 79 | } 80 | 81 | #[derive(ReborrowCopyTraits)] 82 | pub struct I32TupleRef<'a, 'b>(pub i32, pub &'a i32, pub &'b i32); 83 | 84 | #[derive(ReborrowTraits)] 85 | #[Const(I32Ref)] 86 | struct I32RefMut<'a, 'b> { 87 | i: i32, 88 | #[reborrow] 89 | j: &'a mut i32, 90 | #[reborrow] 91 | k: &'b mut i32, 92 | } 93 | 94 | #[derive(ReborrowTraits)] 95 | #[Const(I32TupleRef)] 96 | pub struct I32TupleRefMut<'a, 'b>( 97 | i32, 98 | #[reborrow] &'a mut i32, 99 | #[reborrow] &'b mut i32, 100 | ); 101 | ``` 102 | -------------------------------------------------------------------------------- /example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | reborrow = { path = "../reborrow", features = ["derive"] } 10 | -------------------------------------------------------------------------------- /example/src/main.rs: -------------------------------------------------------------------------------- 1 | use reborrow::{IntoConst, Reborrow, ReborrowMut, ReborrowTraits}; 2 | 3 | mod shared { 4 | use reborrow::ReborrowCopyTraits; 5 | 6 | #[derive(ReborrowCopyTraits)] 7 | pub struct I32Ref<'a, 'b> { 8 | pub i: i32, 9 | pub j: &'a i32, 10 | pub k: &'b i32, 11 | } 12 | 13 | #[derive(ReborrowCopyTraits)] 14 | pub struct I32TupleRef<'a, 'b>(pub i32, pub &'a i32, pub &'b i32); 15 | 16 | #[derive(ReborrowCopyTraits)] 17 | pub struct Ref<'a, 'b, T> { 18 | pub i: i32, 19 | pub j: &'a T, 20 | pub k: &'b T, 21 | } 22 | } 23 | 24 | #[derive(ReborrowTraits)] 25 | #[Const(shared::I32Ref)] 26 | struct I32RefMut<'a, 'b> { 27 | i: i32, 28 | #[reborrow] 29 | j: &'a mut i32, 30 | #[reborrow] 31 | k: &'b mut i32, 32 | } 33 | 34 | #[derive(ReborrowTraits)] 35 | #[Const(shared::I32TupleRef)] 36 | pub struct I32TupleRefMut<'a, 'b>(i32, #[reborrow] &'a mut i32, #[reborrow] &'b mut i32); 37 | 38 | fn main() { 39 | let i = 0; 40 | let j = &mut 0; 41 | let k = &mut 0; 42 | { 43 | let mut r = I32RefMut { i, j, k }; 44 | let _unused = r.rb_mut(); 45 | let _unused = r.rb(); 46 | let _unused = r.into_const(); 47 | } 48 | 49 | { 50 | let mut r = I32TupleRefMut(i, j, k); 51 | let _unused = r.rb(); 52 | let _unused = r.rb_mut(); 53 | let _unused = r.into_const(); 54 | } 55 | println!("Hello, world!"); 56 | } 57 | -------------------------------------------------------------------------------- /reborrow-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "reborrow-derive" 3 | version = "0.5.2" 4 | edition = "2021" 5 | authors = ["sarah <>"] 6 | description = "Emulate reborrowing for user types." 7 | readme = "../README.md" 8 | repository = "https://github.com/kitegi/reborrow/" 9 | license = "MIT" 10 | keywords = ["reborrow", "lifetime"] 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | proc-macro2 = "1.0" 17 | quote = "1.0" 18 | syn = { version = "1.0" } 19 | -------------------------------------------------------------------------------- /reborrow-derive/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 sarah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /reborrow-derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::{DeriveInput, GenericParam, Lifetime, LifetimeDef}; 3 | 4 | #[proc_macro_derive(ReborrowCopyTraits)] 5 | pub fn derive_reborrow_copy(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 6 | let input = syn::parse_macro_input!(input as DeriveInput); 7 | 8 | let name = &input.ident; 9 | 10 | let reborrowed_lifetime = &LifetimeDef::new(Lifetime::new( 11 | "'__reborrow_lifetime", 12 | proc_macro2::Span::call_site(), 13 | )); 14 | 15 | let mut target_ty_generics = input.generics.clone(); 16 | for lt in target_ty_generics.lifetimes_mut() { 17 | *lt = reborrowed_lifetime.clone(); 18 | } 19 | let target_ty_generics = target_ty_generics.split_for_impl().1; 20 | let mut impl_generics = input.generics.clone(); 21 | impl_generics 22 | .params 23 | .insert(0, GenericParam::Lifetime(reborrowed_lifetime.clone())); 24 | let impl_generics = impl_generics.split_for_impl().0; 25 | 26 | let (orig_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); 27 | 28 | let expanded = quote! { 29 | impl #orig_impl_generics ::core::marker::Copy for #name #ty_generics 30 | #where_clause {} 31 | 32 | impl #orig_impl_generics ::core::clone::Clone for #name #ty_generics 33 | #where_clause 34 | { 35 | #[inline] 36 | fn clone(&self) -> Self { 37 | *self 38 | } 39 | } 40 | 41 | impl #orig_impl_generics ::reborrow::IntoConst for #name #ty_generics 42 | #where_clause 43 | { 44 | type Target = #name #ty_generics; 45 | 46 | #[inline] 47 | fn into_const(self) -> ::Target { 48 | self 49 | } 50 | } 51 | 52 | impl #impl_generics ::reborrow::ReborrowMut<'__reborrow_lifetime> for #name #ty_generics 53 | #where_clause 54 | { 55 | type Target = #name #target_ty_generics; 56 | 57 | #[inline] 58 | fn rb_mut(&'__reborrow_lifetime mut self) -> ::Target { 59 | *self 60 | } 61 | } 62 | 63 | impl #impl_generics ::reborrow::Reborrow<'__reborrow_lifetime> for #name #ty_generics 64 | #where_clause 65 | { 66 | type Target = #name #target_ty_generics; 67 | 68 | #[inline] 69 | fn rb(&'__reborrow_lifetime self) -> ::Target { 70 | *self 71 | } 72 | } 73 | 74 | impl #impl_generics ::reborrow::AsGeneralizedMut< 75 | '__reborrow_lifetime, 76 | >::Target, 77 | > for #name #ty_generics 78 | #where_clause 79 | { 80 | #[inline] 81 | fn as_generalized_mut(&'__reborrow_lifetime mut self) -> >::Target { 82 | *self 83 | } 84 | } 85 | 86 | impl #impl_generics ::reborrow::AsGeneralizedRef< 87 | '__reborrow_lifetime, 88 | >::Target, 89 | > for #name #ty_generics 90 | #where_clause 91 | { 92 | #[inline] 93 | fn as_generalized_ref(&'__reborrow_lifetime self) -> >::Target { 94 | *self 95 | } 96 | } 97 | }; 98 | 99 | expanded.into() 100 | } 101 | 102 | #[proc_macro_derive(ReborrowTraits, attributes(reborrow, Const))] 103 | pub fn derive_reborrow(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 104 | let input = syn::parse_macro_input!(input as DeriveInput); 105 | 106 | let const_name = input 107 | .attrs 108 | .iter() 109 | .find(|&attr| { 110 | let segments = &attr.path.segments; 111 | if let Some(syn::PathSegment { 112 | ident, 113 | arguments: syn::PathArguments::None, 114 | }) = segments.first() 115 | { 116 | ident.to_string() == "Const" 117 | } else { 118 | false 119 | } 120 | }) 121 | .unwrap_or_else(|| panic!("Const reborrowed type must be specified.")); 122 | 123 | let const_name = const_name.tokens.clone(); 124 | let const_name = *syn::parse2::(const_name).unwrap().elem; 125 | 126 | let name = &input.ident; 127 | 128 | let reborrowed_lifetime = &LifetimeDef::new(Lifetime::new( 129 | "'__reborrow_lifetime", 130 | proc_macro2::Span::call_site(), 131 | )); 132 | 133 | let mut target_ty_generics = input.generics.clone(); 134 | for lt in target_ty_generics.lifetimes_mut() { 135 | *lt = reborrowed_lifetime.clone(); 136 | } 137 | let target_ty_generics = target_ty_generics.split_for_impl().1; 138 | 139 | let mut impl_generics = input.generics.clone(); 140 | impl_generics 141 | .params 142 | .insert(0, GenericParam::Lifetime(reborrowed_lifetime.clone())); 143 | let impl_generics = impl_generics.split_for_impl().0; 144 | 145 | let (orig_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); 146 | 147 | let (rb_mut, rb, into_const) = { 148 | let data = input.data; 149 | 150 | match data { 151 | syn::Data::Struct(s) => match s.fields { 152 | syn::Fields::Named(f) => { 153 | let names: Vec<_> = f.named.iter().map(|f| &f.ident).collect(); 154 | let (f0, f1, f2) = unzip3( 155 | f.named 156 | .iter() 157 | .enumerate() 158 | .map(|(i, f)| reborrow_exprs(i, f.clone())), 159 | ); 160 | 161 | ( 162 | quote! { #name:: #target_ty_generics { #(#names: #f0,)* } }, 163 | quote! { #const_name:: #target_ty_generics { #(#names: #f1,)* } }, 164 | quote! { #const_name:: #ty_generics { #(#names: #f2,)* } }, 165 | ) 166 | } 167 | syn::Fields::Unnamed(f) => { 168 | let (f0, f1, f2) = unzip3( 169 | f.unnamed 170 | .iter() 171 | .enumerate() 172 | .map(|(i, f)| reborrow_exprs(i, f.clone())), 173 | ); 174 | 175 | ( 176 | quote! { #name:: #target_ty_generics ( #(#f0,)* ) }, 177 | quote! { #const_name:: #target_ty_generics ( #(#f1,)* ) }, 178 | quote! { #const_name:: #ty_generics ( #(#f2,)* ) }, 179 | ) 180 | } 181 | syn::Fields::Unit => ( 182 | quote! { #name:: #target_ty_generics }, 183 | quote! { #const_name:: #target_ty_generics }, 184 | quote! { #const_name:: #target_ty_generics }, 185 | ), 186 | }, 187 | syn::Data::Enum(_) => panic!("reborrow-derive does not support enums."), 188 | syn::Data::Union(_) => panic!("reborrow-derive does not support unions."), 189 | } 190 | }; 191 | 192 | let expanded = quote! { 193 | impl #orig_impl_generics ::reborrow::IntoConst for #name #ty_generics 194 | #where_clause 195 | { 196 | type Target = #const_name #ty_generics; 197 | 198 | #[inline] 199 | fn into_const(self) -> ::Target { 200 | #into_const 201 | } 202 | } 203 | 204 | impl #impl_generics ::reborrow::ReborrowMut<'__reborrow_lifetime> for #name #ty_generics 205 | #where_clause 206 | { 207 | type Target = #name #target_ty_generics; 208 | 209 | #[inline] 210 | fn rb_mut(&'__reborrow_lifetime mut self) -> ::Target { 211 | #rb_mut 212 | } 213 | } 214 | 215 | impl #impl_generics ::reborrow::Reborrow<'__reborrow_lifetime> for #name #ty_generics 216 | #where_clause 217 | { 218 | type Target = #const_name #target_ty_generics; 219 | 220 | #[inline] 221 | fn rb(&'__reborrow_lifetime self) -> ::Target { 222 | #rb 223 | } 224 | } 225 | 226 | impl #impl_generics ::reborrow::AsGeneralizedMut< 227 | '__reborrow_lifetime, 228 | >::Target, 229 | > for #name #ty_generics 230 | #where_clause 231 | { 232 | #[inline] 233 | fn as_generalized_mut(&'__reborrow_lifetime mut self) -> >::Target { 234 | ::rb_mut(self) 235 | } 236 | } 237 | 238 | impl #impl_generics ::reborrow::AsGeneralizedRef< 239 | '__reborrow_lifetime, 240 | >::Target, 241 | > for #name #ty_generics 242 | #where_clause 243 | { 244 | #[inline] 245 | fn as_generalized_ref(&'__reborrow_lifetime self) -> >::Target { 246 | ::rb(self) 247 | } 248 | } 249 | }; 250 | 251 | expanded.into() 252 | } 253 | 254 | fn unzip3>(iter: I) -> (Vec, Vec, Vec) { 255 | let mut v0 = Vec::new(); 256 | let mut v1 = Vec::new(); 257 | let mut v2 = Vec::new(); 258 | for (a, b, c) in iter { 259 | v0.push(a); 260 | v1.push(b); 261 | v2.push(c); 262 | } 263 | (v0, v1, v2) 264 | } 265 | 266 | fn reborrow_exprs( 267 | idx: usize, 268 | f: syn::Field, 269 | ) -> ( 270 | proc_macro2::TokenStream, 271 | proc_macro2::TokenStream, 272 | proc_macro2::TokenStream, 273 | ) { 274 | let is_reborrowable = f 275 | .attrs 276 | .iter() 277 | .find(|&attr| { 278 | let segments = &attr.path.segments; 279 | if let Some(syn::PathSegment { 280 | ident, 281 | arguments: syn::PathArguments::None, 282 | }) = segments.first() 283 | { 284 | ident.to_string() == "reborrow" 285 | } else { 286 | false 287 | } 288 | }) 289 | .is_some(); 290 | 291 | let idx = syn::Index::from(idx); 292 | 293 | let expr = f 294 | .ident 295 | .map(|ident| quote! { self.#ident }) 296 | .unwrap_or(quote! { self.#idx }); 297 | 298 | if !is_reborrowable { 299 | (quote! {#expr}, quote! {#expr}, quote! {#expr}) 300 | } else { 301 | let ty = f.ty; 302 | ( 303 | quote! { <#ty as ::reborrow::ReborrowMut>::rb_mut(&mut #expr) }, 304 | quote! { <#ty as ::reborrow::Reborrow>::rb(&#expr) }, 305 | quote! { <#ty as ::reborrow::IntoConst>::into_const(#expr) }, 306 | ) 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /reborrow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "reborrow" 3 | version = "0.5.5" 4 | edition = "2021" 5 | authors = ["sarah <>"] 6 | description = "Emulate reborrowing for user types." 7 | readme = "../README.md" 8 | repository = "https://github.com/sarah-ek/reborrow/" 9 | license = "MIT" 10 | keywords = ["reborrow", "lifetime"] 11 | 12 | [dependencies] 13 | reborrow-derive = { version = "0.5", path = "../reborrow-derive", optional = true } 14 | 15 | [features] 16 | default = [] 17 | derive = ["reborrow-derive"] 18 | -------------------------------------------------------------------------------- /reborrow/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 sarah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /reborrow/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Emulate reborrowing for user types. 2 | //! 3 | //! A generalized reference is a type that has reference semantics, without actually being 4 | //! a native Rust reference (like `&T` and `&mut T`). e.g.: 5 | //! 6 | //! ``` 7 | //! struct MyRefMut<'borrow> { 8 | //! a: &'borrow mut i32, 9 | //! b: &'borrow mut i32, 10 | //! } 11 | //! ``` 12 | //! 13 | //! Given a `&'a` \[mut\] reference of a `&'b` view over some owned object, 14 | //! reborrowing it means getting an active `&'a` view over the owned object, 15 | //! which renders the original reference inactive until it's dropped, at which point 16 | //! the original reference becomes active again. 17 | //! 18 | //! This crate defines traits to make generalized references more ergonomic to use by giving the 19 | //! ability to borrow and reborrow them. 20 | //! 21 | //! # Examples: 22 | //! This fails to compile since we can't use a non-`Copy` value after it's moved. 23 | //! ```compile_fail 24 | //! fn takes_mut_option(o: Option<&mut i32>) {} 25 | //! 26 | //! let mut x = 0; 27 | //! let o = Some(&mut x); 28 | //! takes_mut_option(o); // `o` is moved here, 29 | //! takes_mut_option(o); // so it can't be used here. 30 | //! ``` 31 | //! 32 | //! This can be worked around by unwrapping the option, reborrowing it, and then wrapping it again. 33 | //! ``` 34 | //! fn takes_mut_option(o: Option<&mut i32>) {} 35 | //! 36 | //! let mut x = 0; 37 | //! let mut o = Some(&mut x); 38 | //! takes_mut_option(o.as_mut().map(|r| &mut **r)); // "Reborrowing" the `Option` 39 | //! takes_mut_option(o.as_mut().map(|r| &mut **r)); // allows us to use it later on. 40 | //! drop(o); // can still be used here 41 | //! ``` 42 | //! 43 | //! Using this crate, this can be shortened to 44 | //! ``` 45 | //! use reborrow::ReborrowMut; 46 | //! 47 | //! fn takes_mut_option(o: Option<&mut i32>) {} 48 | //! 49 | //! let mut x = 0; 50 | //! let mut o = Some(&mut x); 51 | //! takes_mut_option(o.rb_mut()); // "Reborrowing" the `Option` 52 | //! takes_mut_option(o.rb_mut()); // allows us to use it later on. 53 | //! drop(o); // can still be used here 54 | //! ``` 55 | //! 56 | //! The derive macro can be used with structs or tuple structs, on the mutable variant and 57 | //! generates the trait definitions for [`Reborrow`], [`ReborrowMut`], and [`IntoConst`]. 58 | //! 59 | //! ``` 60 | //! use reborrow::{ReborrowCopyTraits, ReborrowTraits}; 61 | //! 62 | //! #[derive(ReborrowCopyTraits)] 63 | //! pub struct I32Ref<'a, 'b> { 64 | //! pub i: i32, 65 | //! pub j: &'a i32, 66 | //! pub k: &'b i32, 67 | //! } 68 | //! 69 | //! #[derive(ReborrowCopyTraits)] 70 | //! pub struct I32TupleRef<'a, 'b>(pub i32, pub &'a i32, pub &'b i32); 71 | //! 72 | //! #[derive(ReborrowTraits)] 73 | //! #[Const(I32Ref)] 74 | //! struct I32RefMut<'a, 'b> { 75 | //! i: i32, 76 | //! #[reborrow] 77 | //! j: &'a mut i32, 78 | //! #[reborrow] 79 | //! k: &'b mut i32, 80 | //! } 81 | //! 82 | //! #[derive(ReborrowTraits)] 83 | //! #[Const(I32TupleRef)] 84 | //! pub struct I32TupleRefMut<'a, 'b>( 85 | //! i32, 86 | //! #[reborrow] &'a mut i32, 87 | //! #[reborrow] &'b mut i32, 88 | //! ); 89 | //! ``` 90 | #![no_std] 91 | 92 | // _Outlives: suggestion from /u/YatoRust 93 | // https://www.reddit.com/r/rust/comments/tjzy97/reborrow_emulating_reborrowing_for_user_types/i1nco4i/ 94 | 95 | #[cfg(feature = "derive")] 96 | pub use reborrow_derive::{ReborrowCopyTraits, ReborrowTraits}; 97 | 98 | /// Immutable reborrowing. 99 | pub trait Reborrow<'short, _Outlives = &'short Self> { 100 | type Target; 101 | #[must_use] 102 | fn rb(&'short self) -> Self::Target; 103 | } 104 | 105 | /// Mutable reborrowing. 106 | pub trait ReborrowMut<'short, _Outlives = &'short Self> { 107 | type Target; 108 | #[must_use] 109 | fn rb_mut(&'short mut self) -> Self::Target; 110 | } 111 | 112 | /// Consume a mutable reference to produce an immutable one. 113 | pub trait IntoConst { 114 | type Target; 115 | #[must_use] 116 | fn into_const(self) -> Self::Target; 117 | } 118 | 119 | /// This trait is similar to [`std::convert::AsRef`], but works with generalized reference 120 | /// types, instead of being limited to native Rust references. 121 | pub trait AsGeneralizedRef<'short, Target, _Outlives = &'short Self> { 122 | #[must_use] 123 | fn as_generalized_ref(&'short self) -> Target; 124 | } 125 | 126 | /// This trait is similar to [`std::convert::AsMut`], but works with generalized reference 127 | /// types, instead of being limited to native Rust references. 128 | pub trait AsGeneralizedMut<'short, Target, _Outlives = &'short Self> { 129 | #[must_use] 130 | fn as_generalized_mut(&'short mut self) -> Target; 131 | } 132 | 133 | impl<'short, T: ?Sized + AsRef, Target: ?Sized> AsGeneralizedRef<'short, &'short Target> 134 | for T 135 | { 136 | #[inline] 137 | fn as_generalized_ref(&'short self) -> &'short Target { 138 | self.as_ref() 139 | } 140 | } 141 | 142 | impl<'short, T: ?Sized + AsMut, Target: ?Sized> AsGeneralizedMut<'short, &'short mut Target> 143 | for T 144 | { 145 | #[inline] 146 | fn as_generalized_mut(&'short mut self) -> &'short mut Target { 147 | self.as_mut() 148 | } 149 | } 150 | 151 | impl<'short, 'a, T> Reborrow<'short> for &'a T 152 | where 153 | T: ?Sized, 154 | { 155 | type Target = &'short T; 156 | 157 | #[inline] 158 | fn rb(&'short self) -> Self::Target { 159 | *self 160 | } 161 | } 162 | 163 | impl<'short, 'a, T> ReborrowMut<'short> for &'a T 164 | where 165 | T: ?Sized, 166 | { 167 | type Target = &'short T; 168 | 169 | #[inline] 170 | fn rb_mut(&'short mut self) -> Self::Target { 171 | *self 172 | } 173 | } 174 | 175 | impl<'a, T> IntoConst for &'a T 176 | where 177 | T: ?Sized, 178 | { 179 | type Target = &'a T; 180 | 181 | #[inline] 182 | fn into_const(self) -> Self::Target { 183 | self 184 | } 185 | } 186 | 187 | impl<'short, 'a, T> Reborrow<'short> for &'a mut T 188 | where 189 | T: ?Sized, 190 | { 191 | type Target = &'short T; 192 | 193 | #[inline] 194 | fn rb(&'short self) -> Self::Target { 195 | *self 196 | } 197 | } 198 | 199 | impl<'short, 'a, T> ReborrowMut<'short> for &'a mut T 200 | where 201 | T: ?Sized, 202 | { 203 | type Target = &'short mut T; 204 | 205 | #[inline] 206 | fn rb_mut(&'short mut self) -> Self::Target { 207 | *self 208 | } 209 | } 210 | 211 | impl<'a, T> IntoConst for &'a mut T 212 | where 213 | T: ?Sized, 214 | { 215 | type Target = &'a T; 216 | 217 | #[inline] 218 | fn into_const(self) -> Self::Target { 219 | self 220 | } 221 | } 222 | 223 | impl<'short, T> Reborrow<'short> for Option 224 | where 225 | T: Reborrow<'short>, 226 | { 227 | type Target = Option; 228 | 229 | #[inline] 230 | fn rb(&'short self) -> Self::Target { 231 | match self { 232 | &None => None, 233 | &Some(ref x) => Some(x.rb()), 234 | } 235 | } 236 | } 237 | 238 | impl<'short, T> ReborrowMut<'short> for Option 239 | where 240 | T: ReborrowMut<'short>, 241 | { 242 | type Target = Option; 243 | 244 | #[inline] 245 | fn rb_mut(&'short mut self) -> Self::Target { 246 | match self { 247 | &mut None => None, 248 | &mut Some(ref mut x) => Some(x.rb_mut()), 249 | } 250 | } 251 | } 252 | 253 | impl IntoConst for Option 254 | where 255 | T: IntoConst, 256 | { 257 | type Target = Option; 258 | 259 | #[inline] 260 | fn into_const(self) -> Self::Target { 261 | match self { 262 | None => None, 263 | Some(x) => Some(x.into_const()), 264 | } 265 | } 266 | } 267 | 268 | impl<'short, T: AsGeneralizedRef<'short, Target>, Target> AsGeneralizedRef<'short, Option> 269 | for Option 270 | { 271 | #[inline] 272 | fn as_generalized_ref(&'short self) -> Option { 273 | match self { 274 | None => None, 275 | &Some(ref x) => Some(x.as_generalized_ref()), 276 | } 277 | } 278 | } 279 | 280 | impl<'short, T: AsGeneralizedMut<'short, Target>, Target> AsGeneralizedMut<'short, Option> 281 | for Option 282 | { 283 | #[inline] 284 | fn as_generalized_mut(&'short mut self) -> Option { 285 | match self { 286 | None => None, 287 | &mut Some(ref mut x) => Some(x.as_generalized_mut()), 288 | } 289 | } 290 | } 291 | 292 | #[cfg(test)] 293 | mod tests { 294 | use super::*; 295 | 296 | #[test] 297 | fn option() { 298 | let mut a = 0; 299 | let mut opt = Some(&mut a); 300 | let opt_mut = &mut opt; 301 | let _ = opt_mut.rb_mut(); 302 | } 303 | 304 | #[test] 305 | fn custom_view_type() { 306 | struct MyViewType<'a> { 307 | r: &'a mut i32, 308 | } 309 | 310 | impl<'short, 'a> ReborrowMut<'short> for MyViewType<'a> { 311 | type Target = MyViewType<'short>; 312 | 313 | fn rb_mut(&'short mut self) -> Self::Target { 314 | MyViewType { r: self.r } 315 | } 316 | } 317 | 318 | fn takes_mut_option(_o: Option) {} 319 | 320 | let mut x = 0; 321 | let mut o = Some(MyViewType { r: &mut x }); 322 | takes_mut_option(o.rb_mut()); 323 | takes_mut_option(o.rb_mut()); 324 | drop(o); 325 | } 326 | 327 | #[test] 328 | fn as_ref() { 329 | let v = [()]; 330 | let _r: &[()] = v.as_generalized_ref(); 331 | } 332 | } 333 | --------------------------------------------------------------------------------