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}