reborrow-derive-0.5.2/.cargo_vcs_info.json0000644000000001550000000000100141560ustar { "git": { "sha1": "b715378034b5e5bc809617ef6505c74359c79ce8" }, "path_in_vcs": "reborrow-derive" }reborrow-derive-0.5.2/Cargo.toml0000644000000016110000000000100121520ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "reborrow-derive" version = "0.5.2" authors = ["sarah <>"] description = "Emulate reborrowing for user types." readme = "README.md" keywords = [ "reborrow", "lifetime", ] license = "MIT" repository = "https://github.com/kitegi/reborrow/" resolver = "1" [lib] proc-macro = true [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = "1.0" reborrow-derive-0.5.2/Cargo.toml.orig000064400000000000000000000005651046102023000156420ustar 00000000000000[package] name = "reborrow-derive" version = "0.5.2" edition = "2021" authors = ["sarah <>"] description = "Emulate reborrowing for user types." readme = "../README.md" repository = "https://github.com/kitegi/reborrow/" license = "MIT" keywords = ["reborrow", "lifetime"] [lib] proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" syn = { version = "1.0" } reborrow-derive-0.5.2/LICENSE000064400000000000000000000020461046102023000137540ustar 00000000000000MIT License Copyright (c) 2022 sarah Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. reborrow-derive-0.5.2/README.md000064400000000000000000000053411046102023000142270ustar 00000000000000Emulate reborrowing for user types. A generalized reference is a type that has reference semantics, without actually being a native Rust reference (like `&T` and `&mut T`). e.g.: ```rust struct MyRefMut<'borrow> { a: &'borrow mut i32, b: &'borrow mut i32, } ``` Given a `&'a` \[mut\] reference of a `&'b` view over some owned object, reborrowing it means getting an active `&'a` view over the owned object, which renders the original reference inactive until it's dropped, at which point the original reference becomes active again. This crate defines traits to make generalized references more ergonomic to use by giving the ability to borrow and reborrow them. # Features `derive`: This imports a derive macro helper for implementing reborrow for user types. It can be used with a `Ref/RefMut` pair of structs/tuple structs with the same member names, one containing shared references and the other mutable references. The shared variant must be `Copy`, and the macro is used on the mutable variant and generates the relevant traits for both types. # Examples This fails to compile since we can't use a non-`Copy` value after it's moved. ```rust fn takes_mut_option(o: Option<&mut i32>) {} let mut x = 0; let o = Some(&mut x); takes_mut_option(o); // `o` is moved here, takes_mut_option(o); // so it can't be used here. ``` This can be worked around by unwrapping the option, reborrowing it, and then wrapping it again. ```rust fn takes_mut_option(o: Option<&mut i32>) {} let mut x = 0; let mut o = Some(&mut x); takes_mut_option(o.as_mut().map(|r| &mut **r)); // "Reborrowing" the `Option` takes_mut_option(o.as_mut().map(|r| &mut **r)); // allows us to use it later on. drop(o); // can still be used here ``` Using this crate, this can be shortened to ```rust use reborrow::ReborrowMut; fn takes_mut_option(o: Option<&mut i32>) {} let mut x = 0; let mut o = Some(&mut x); takes_mut_option(o.rb_mut()); // "Reborrowing" the `Option` takes_mut_option(o.rb_mut()); // allows us to use it later on. drop(o); // can still be used here ``` The derive macro can be used with structs or tuple structs, and generates the trait definitions for `Reborrow` and `ReborrowMut`. ```rust use reborrow::{ReborrowCopyTraits, ReborrowTraits}; #[derive(ReborrowCopyTraits)] pub struct I32Ref<'a, 'b> { pub i: i32, pub j: &'a i32, pub k: &'b i32, } #[derive(ReborrowCopyTraits)] pub struct I32TupleRef<'a, 'b>(pub i32, pub &'a i32, pub &'b i32); #[derive(ReborrowTraits)] #[Const(I32Ref)] struct I32RefMut<'a, 'b> { i: i32, #[reborrow] j: &'a mut i32, #[reborrow] k: &'b mut i32, } #[derive(ReborrowTraits)] #[Const(I32TupleRef)] pub struct I32TupleRefMut<'a, 'b>( i32, #[reborrow] &'a mut i32, #[reborrow] &'b mut i32, ); ``` reborrow-derive-0.5.2/src/lib.rs000064400000000000000000000236151046102023000146570ustar 00000000000000use quote::quote; use syn::{DeriveInput, GenericParam, Lifetime, LifetimeDef}; #[proc_macro_derive(ReborrowCopyTraits)] pub fn derive_reborrow_copy(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as DeriveInput); let name = &input.ident; let reborrowed_lifetime = &LifetimeDef::new(Lifetime::new( "'__reborrow_lifetime", proc_macro2::Span::call_site(), )); let mut target_ty_generics = input.generics.clone(); for lt in target_ty_generics.lifetimes_mut() { *lt = reborrowed_lifetime.clone(); } let target_ty_generics = target_ty_generics.split_for_impl().1; let mut impl_generics = input.generics.clone(); impl_generics .params .insert(0, GenericParam::Lifetime(reborrowed_lifetime.clone())); let impl_generics = impl_generics.split_for_impl().0; let (orig_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let expanded = quote! { impl #orig_impl_generics ::core::marker::Copy for #name #ty_generics #where_clause {} impl #orig_impl_generics ::core::clone::Clone for #name #ty_generics #where_clause { #[inline] fn clone(&self) -> Self { *self } } impl #orig_impl_generics ::reborrow::IntoConst for #name #ty_generics #where_clause { type Target = #name #ty_generics; #[inline] fn into_const(self) -> ::Target { self } } impl #impl_generics ::reborrow::ReborrowMut<'__reborrow_lifetime> for #name #ty_generics #where_clause { type Target = #name #target_ty_generics; #[inline] fn rb_mut(&'__reborrow_lifetime mut self) -> ::Target { *self } } impl #impl_generics ::reborrow::Reborrow<'__reborrow_lifetime> for #name #ty_generics #where_clause { type Target = #name #target_ty_generics; #[inline] fn rb(&'__reborrow_lifetime self) -> ::Target { *self } } impl #impl_generics ::reborrow::AsGeneralizedMut< '__reborrow_lifetime, >::Target, > for #name #ty_generics #where_clause { #[inline] fn as_generalized_mut(&'__reborrow_lifetime mut self) -> >::Target { *self } } impl #impl_generics ::reborrow::AsGeneralizedRef< '__reborrow_lifetime, >::Target, > for #name #ty_generics #where_clause { #[inline] fn as_generalized_ref(&'__reborrow_lifetime self) -> >::Target { *self } } }; expanded.into() } #[proc_macro_derive(ReborrowTraits, attributes(reborrow, Const))] pub fn derive_reborrow(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as DeriveInput); let const_name = input .attrs .iter() .find(|&attr| { let segments = &attr.path.segments; if let Some(syn::PathSegment { ident, arguments: syn::PathArguments::None, }) = segments.first() { ident.to_string() == "Const" } else { false } }) .unwrap_or_else(|| panic!("Const reborrowed type must be specified.")); let const_name = const_name.tokens.clone(); let const_name = *syn::parse2::(const_name).unwrap().elem; let name = &input.ident; let reborrowed_lifetime = &LifetimeDef::new(Lifetime::new( "'__reborrow_lifetime", proc_macro2::Span::call_site(), )); let mut target_ty_generics = input.generics.clone(); for lt in target_ty_generics.lifetimes_mut() { *lt = reborrowed_lifetime.clone(); } let target_ty_generics = target_ty_generics.split_for_impl().1; let mut impl_generics = input.generics.clone(); impl_generics .params .insert(0, GenericParam::Lifetime(reborrowed_lifetime.clone())); let impl_generics = impl_generics.split_for_impl().0; let (orig_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let (rb_mut, rb, into_const) = { let data = input.data; match data { syn::Data::Struct(s) => match s.fields { syn::Fields::Named(f) => { let names: Vec<_> = f.named.iter().map(|f| &f.ident).collect(); let (f0, f1, f2) = unzip3( f.named .iter() .enumerate() .map(|(i, f)| reborrow_exprs(i, f.clone())), ); ( quote! { #name:: #target_ty_generics { #(#names: #f0,)* } }, quote! { #const_name:: #target_ty_generics { #(#names: #f1,)* } }, quote! { #const_name:: #ty_generics { #(#names: #f2,)* } }, ) } syn::Fields::Unnamed(f) => { let (f0, f1, f2) = unzip3( f.unnamed .iter() .enumerate() .map(|(i, f)| reborrow_exprs(i, f.clone())), ); ( quote! { #name:: #target_ty_generics ( #(#f0,)* ) }, quote! { #const_name:: #target_ty_generics ( #(#f1,)* ) }, quote! { #const_name:: #ty_generics ( #(#f2,)* ) }, ) } syn::Fields::Unit => ( quote! { #name:: #target_ty_generics }, quote! { #const_name:: #target_ty_generics }, quote! { #const_name:: #target_ty_generics }, ), }, syn::Data::Enum(_) => panic!("reborrow-derive does not support enums."), syn::Data::Union(_) => panic!("reborrow-derive does not support unions."), } }; let expanded = quote! { impl #orig_impl_generics ::reborrow::IntoConst for #name #ty_generics #where_clause { type Target = #const_name #ty_generics; #[inline] fn into_const(self) -> ::Target { #into_const } } impl #impl_generics ::reborrow::ReborrowMut<'__reborrow_lifetime> for #name #ty_generics #where_clause { type Target = #name #target_ty_generics; #[inline] fn rb_mut(&'__reborrow_lifetime mut self) -> ::Target { #rb_mut } } impl #impl_generics ::reborrow::Reborrow<'__reborrow_lifetime> for #name #ty_generics #where_clause { type Target = #const_name #target_ty_generics; #[inline] fn rb(&'__reborrow_lifetime self) -> ::Target { #rb } } impl #impl_generics ::reborrow::AsGeneralizedMut< '__reborrow_lifetime, >::Target, > for #name #ty_generics #where_clause { #[inline] fn as_generalized_mut(&'__reborrow_lifetime mut self) -> >::Target { ::rb_mut(self) } } impl #impl_generics ::reborrow::AsGeneralizedRef< '__reborrow_lifetime, >::Target, > for #name #ty_generics #where_clause { #[inline] fn as_generalized_ref(&'__reborrow_lifetime self) -> >::Target { ::rb(self) } } }; expanded.into() } fn unzip3>(iter: I) -> (Vec, Vec, Vec) { let mut v0 = Vec::new(); let mut v1 = Vec::new(); let mut v2 = Vec::new(); for (a, b, c) in iter { v0.push(a); v1.push(b); v2.push(c); } (v0, v1, v2) } fn reborrow_exprs( idx: usize, f: syn::Field, ) -> ( proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream, ) { let is_reborrowable = f .attrs .iter() .find(|&attr| { let segments = &attr.path.segments; if let Some(syn::PathSegment { ident, arguments: syn::PathArguments::None, }) = segments.first() { ident.to_string() == "reborrow" } else { false } }) .is_some(); let idx = syn::Index::from(idx); let expr = f .ident .map(|ident| quote! { self.#ident }) .unwrap_or(quote! { self.#idx }); if !is_reborrowable { (quote! {#expr}, quote! {#expr}, quote! {#expr}) } else { let ty = f.ty; ( quote! { <#ty as ::reborrow::ReborrowMut>::rb_mut(&mut #expr) }, quote! { <#ty as ::reborrow::Reborrow>::rb(&#expr) }, quote! { <#ty as ::reborrow::IntoConst>::into_const(#expr) }, ) } }