Skip to main content

structural/
field_cloner.rs

1use crate::{
2    field::{DropFields, GetField, GetVariantField, IntoField, IntoVariantField, MovedOutFields},
3    TStr,
4};
5
6use core_extensions::ConstDefault;
7
8/// Wrapper that emulates by-value access to fields by cloning them.
9///
10/// This allows using types that only provide shared access to fields
11/// (implementing `GetField`/`GetVariantField`)
12/// to be passed to functions expecting by-value access to them
13/// (requiring `IntoField`/`IntoVariantField`),
14/// by cloning those fields.
15///
16/// # Struct Example
17///
18/// ```rust
19/// use structural::{FieldCloner, Structural, StructuralExt, fp, structural_alias};
20///
21/// # fn main(){
22///
23/// let expected = ("what".to_string(), vec![0,1,2]);
24///
25/// let this = TheStruct{foo: "what".to_string(), bar: vec![0,1,2]};
26///
27/// // This doesn't compile,because `TheStruct` only provides shared access to the fields,
28/// // implementing `GetField` to access both the `foo` and `bar` fields.
29/// //
30/// // assert_eq!( into_foo_bar(this), expected.clone() );
31///
32/// assert_eq!( into_foo_bar(FieldCloner(this.clone())), expected.clone() );
33///
34/// assert_eq!( into_foo_bar(FieldCloner(&this)), expected.clone() );
35///
36/// assert_eq!( into_foo_bar(FieldCloner(&&&&&this)), expected.clone() );
37///
38/// # }
39///
40/// fn into_foo_bar<P, T>(this: P)-> (String, Vec<T>)
41/// where
42///     P: TypeMove<String, Vec<T>>,
43/// {
44///     this.into_fields(fp!(foo, bar))
45/// }
46///
47/// #[derive(Structural,Clone)]
48/// // Makes this struct only implement `GetField` for the fields,
49/// // providing shared access to them.
50/// #[struc(access="ref")]
51/// struct TheStruct<T, U>{
52///     pub foo: T,
53///     pub bar: U,
54/// }
55///
56/// structural::structural_alias!{
57///     // The same fields as `TheStruct`, with shared and by-value access to the fields.
58///     //
59///     // This trait isn't implemented by `TheStruct` because it only
60///     // provides shared access to the fields.
61///     trait TypeMove<T, U>{
62///         move foo: T,
63///         move bar: U,
64///     }
65/// }
66/// ```
67///
68/// # Enum Example
69///
70#[cfg_attr(feature = "alloc", doc = "```rust")]
71#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
72/// use structural::{FieldCloner, Structural, StructuralExt, fp, structural_alias};
73///
74/// # fn main(){
75///
76/// {
77///     let expected = Some((vec!["foo","bar"], [0, 1, 2]));
78///    
79///     let this = TheEnum::Both(vec!["foo","bar"], [0, 1, 2]);
80///    
81///     // This doesn't compile,because `TheEnum` only provides shared access to the fields,
82///     // implementing `GetField` to access both the `foo` and `bar` fields.
83///     //
84///     // assert_eq!( into_both(Box::new(this)), expected.clone() );
85///    
86///     assert_eq!( into_both(Box::new(FieldCloner(this.clone()))), expected.clone() );
87///    
88///     assert_eq!( into_both(Box::new(FieldCloner(&this))), expected.clone() );
89///    
90///     assert_eq!( into_both(Box::new(FieldCloner(&&&&&this))), expected.clone() );
91/// }
92/// {
93///     let this = TheEnum::Left{left: vec!["foo","bar"]};
94///    
95///     assert_eq!( into_both(Box::new(FieldCloner(this.clone()))), None );
96///    
97///     assert_eq!( into_both(Box::new(FieldCloner(&this))), None );
98///    
99///     assert_eq!( into_both(Box::new(FieldCloner(&&&&&this))), None );
100/// }
101///
102/// # }
103///
104/// fn into_both<'a,T>(
105///     this: Box<dyn TypeMove<Vec<T>, [u32;3]> + 'a>
106/// )-> Option<(Vec<T>, [u32;3])> {
107///     this.into_fields(fp!(::Both=>0,1))
108/// }
109///
110/// #[derive(Structural, Clone)]
111/// // Makes this enum only implement `GetVariantField` for the fields,
112/// // providing shared access to them.
113/// #[struc(access="ref")]
114/// pub enum TheEnum<L, R> {
115///     Both(L, R),
116///     Left{left: L},
117///     Right{right: R},
118/// }
119///
120/// structural::structural_alias!{
121///     // The same fields as `TheEnum`, with shared and by-value access to the fields.
122///     //
123///     // This trait isn't implemented by `TheEnum` because it only
124///     // provides shared access to the fields.
125///     trait TypeMove<L, R>{
126///         move Both(L, R),
127///         move Left{left: L},
128///         move Right{right: R},
129///     }
130/// }
131/// ```
132#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
133#[repr(transparent)]
134pub struct FieldCloner<T>(pub T);
135
136impl<T> FieldCloner<T> {
137    /// Turns a `&FieldCloner<T>` into a `FieldCloner<&T>`.
138    ///
139    /// # Struct Example
140    ///
141    /// ```rust
142    /// use structural::{FieldCloner, StructuralExt, fp};
143    /// use structural::for_examples::{FooBarRef, FooBarMove_SI};
144    ///
145    /// let this = FieldCloner(FooBarRef{foo: 100, bar: "baz"});
146    ///
147    /// assert_eq!( into_foo(this.as_ref()), 100 );
148    ///
149    /// fn into_foo<T, U>(this: impl FooBarMove_SI<T, U>)-> T {
150    ///     this.into_field(fp!(foo))
151    /// }
152    ///
153    /// ```
154    ///
155    /// # Enum Example
156    ///
157    /// ```rust
158    /// use structural::{FieldCloner, StructuralExt, fp};
159    /// use structural::for_examples::{EnumRef, EnumMove_SI};
160    ///
161    /// let this = FieldCloner(EnumRef::Left{left: 10});
162    ///
163    /// assert_eq!( into_left(this.as_ref()), Some(10) );
164    ///
165    /// fn into_left(this: impl EnumMove_SI<u32, bool>)-> Option<u32> {
166    ///     this.into_field(fp!(::Left.left))
167    /// }
168    ///
169    /// ```
170    ///
171    #[inline(always)]
172    pub fn as_ref(&self) -> FieldCloner<&T> {
173        FieldCloner(&self.0)
174    }
175
176    /// Turns a `&mut FieldCloner<T>` into a `FieldCloner<&mut T>`.
177    ///
178    /// # Struct Example
179    ///
180    /// ```rust
181    /// use structural::{FieldCloner, StructuralExt, fp};
182    /// use structural::for_examples::{FooBarRef, FooBarMove_SI};
183    ///
184    /// let this = FieldCloner(FooBarRef{foo: 100, bar: "baz"});
185    ///
186    /// assert_eq!( into_bar(this.as_ref()), "baz" );
187    ///
188    /// fn into_bar<T, U>(this: impl FooBarMove_SI<T, U>)-> U {
189    ///     this.into_field(fp!(bar))
190    /// }
191    ///
192    /// ```
193    ///
194    /// # Enum Example
195    ///
196    /// ```rust
197    /// use structural::{FieldCloner, StructuralExt, fp};
198    /// use structural::for_examples::{EnumRef, EnumMove_SI};
199    ///
200    /// let mut this = FieldCloner(EnumRef::Right{right: false});
201    ///
202    /// assert_eq!( into_right(this.as_mut()), Some(false) );
203    ///
204    /// fn into_right(this: impl EnumMove_SI<u32, bool>)-> Option<bool> {
205    ///     this.into_field(fp!(::Right.right))
206    /// }
207    ///
208    /// ```
209    ///
210    #[inline(always)]
211    pub fn as_mut(&mut self) -> FieldCloner<&mut T> {
212        FieldCloner(&mut self.0)
213    }
214
215    /// Transforms the wrapped value with the `func` function.
216    ///
217    ///
218    #[inline(always)]
219    pub fn map<F, U>(self, f: F) -> FieldCloner<U>
220    where
221        F: FnOnce(T) -> U,
222    {
223        FieldCloner(f(self.0))
224    }
225
226    /// Calls `func` with `self`,rewrapping its return value in a `FieldCloner<U>`
227    #[inline(always)]
228    pub fn then<F, U>(self, f: F) -> FieldCloner<U>
229    where
230        F: FnOnce(Self) -> U,
231    {
232        FieldCloner(f(self))
233    }
234}
235
236impl<T: Clone> FieldCloner<&T> {
237    /// Maps the wrapped reference into a clone.
238    #[inline(always)]
239    pub fn cloned(self) -> FieldCloner<T> {
240        FieldCloner((*self.0).clone())
241    }
242}
243
244impl<T: Clone> FieldCloner<&mut T> {
245    /// Maps the wrapped mutable reference into a clone.
246    #[inline(always)]
247    pub fn cloned(self) -> FieldCloner<T> {
248        FieldCloner((*self.0).clone())
249    }
250}
251
252////////////////////////////////////////////////////////////////////////////////
253
254impl<T> ConstDefault for FieldCloner<T>
255where
256    T: ConstDefault,
257{
258    const DEFAULT: Self = FieldCloner(T::DEFAULT);
259}
260
261////////////////////////////////////////////////////////////////////////////////
262
263unsafe impl<T, P> IntoField<P> for FieldCloner<T>
264where
265    T: GetField<P>,
266    T::Ty: Clone,
267{
268    #[inline(always)]
269    fn into_field_(self, path: P) -> Self::Ty {
270        self.0.get_field_(path).clone()
271    }
272
273    #[inline(always)]
274    unsafe fn move_out_field_(&mut self, path: P, _: &mut MovedOutFields) -> Self::Ty {
275        self.0.get_field_(path).clone()
276    }
277}
278
279unsafe impl<T, V, F> IntoVariantField<TStr<V>, F> for FieldCloner<T>
280where
281    T: GetVariantField<TStr<V>, F>,
282    T::Ty: Clone,
283{
284    #[inline(always)]
285    fn into_vfield_(self, variant_name: TStr<V>, field_name: F) -> Option<Self::Ty> {
286        match self.0.get_vfield_(variant_name, field_name) {
287            Some(x) => Some(x.clone()),
288            _ => None,
289        }
290    }
291
292    #[inline(always)]
293    unsafe fn move_out_vfield_(
294        &mut self,
295        variant_name: TStr<V>,
296        field_name: F,
297        _: &mut MovedOutFields,
298    ) -> Option<Self::Ty> {
299        match self.0.get_vfield_(variant_name, field_name) {
300            Some(x) => Some(x.clone()),
301            _ => None,
302        }
303    }
304}
305
306unsafe impl<T> DropFields for FieldCloner<T> {
307    #[inline(always)]
308    fn pre_move(&mut self) {}
309
310    #[inline(always)]
311    unsafe fn drop_fields(&mut self, _: MovedOutFields) {
312        // No field was moved out, so we can just drop Self.
313        std_::ptr::drop_in_place(self);
314    }
315}
316
317unsafe_delegate_structural_with! {
318    impl[T,] FieldCloner<T>
319    where[]
320
321    self_ident=this;
322    specialization_params(Sized);
323    delegating_to_type=T;
324
325    GetField { &this.0 }
326
327    GetFieldMut{
328        &mut this.0
329    }
330    as_delegating_raw{
331        this as *mut T
332    }
333
334    FromStructural {
335        constructor = FieldCloner;
336    }
337}