structural/structural_ext.rs
1use crate::{
2 convert::{IntoStructural, TryFromError, TryIntoStructural},
3 enums::IsVariant,
4 field::{
5 NormalizeFields, NormalizeFieldsOut, RevGetFieldImpl, RevGetFieldMutImpl, RevGetMultiField,
6 RevGetMultiFieldMut, RevGetMultiFieldMutOut, RevGetMultiFieldOut, RevIntoFieldImpl,
7 RevIntoMultiField, RevIntoMultiFieldOut,
8 },
9 path::IsTStr,
10};
11
12use core_extensions::collection_traits::{Cloned, ClonedOut};
13
14/// A trait defining the primary way to call methods from structural traits.
15///
16/// For a wrapper type that defines inherent methods equivalent to the ones in this trait,
17/// you can use the [`StrucWrapper`] wrapper type.
18///
19/// [`StrucWrapper`]: ./struct.StrucWrapper.html
20pub trait StructuralExt {
21 /// Gets a reference to a field,determined by `path`.
22 ///
23 /// This is named `field_` instead of `field`
24 /// because `field` collides with the `DebugTuple`/`DebugStruct` method
25 ///
26 /// # Example
27 ///
28 /// ```
29 /// use structural::{StructuralExt,fp,structural_alias};
30 ///
31 /// structural_alias!{
32 /// trait EvenFields<A,B,C>{
33 /// 0:A,
34 /// 2:B,
35 /// 4:C,
36 /// }
37 /// }
38 ///
39 /// fn with_even<T>(this:&T)
40 /// where
41 /// T:EvenFields<u32,u32,u32>
42 /// {
43 /// assert_eq!( this.field_(fp!(0)), &1 );
44 /// assert_eq!( this.field_(fp!(2)), &2 );
45 /// assert_eq!( this.field_(fp!(4)), &5 );
46 /// }
47 ///
48 /// fn main(){
49 /// with_even( &(1,0,2,0,5) );
50 /// with_even( &(1,0,2,0,5,0) );
51 /// with_even( &(1,0,2,0,5,0,0) );
52 /// with_even( &(1,0,2,0,5,0,0,0) );
53 /// }
54 ///
55 /// ```
56 ///
57 /// # Enum Example
58 ///
59 /// ```
60 /// use structural::{StructuralExt,Structural,fp};
61 ///
62 /// with_circle( &Shape::Circle{ x:3, y:5, radius:8 } );
63 /// with_circle( &MoreShapes::Circle{ x:3, y:5, radius:8 } );
64 ///
65 /// fn with_circle<T>(circle:&T)
66 /// where
67 /// // `Shape_SI` was generated for Shape by the `Structural` derive.
68 /// T: Shape_SI
69 /// {
70 /// assert_eq!( circle.field_(fp!(::Circle.x)), Some(&3) );
71 /// assert_eq!( circle.field_(fp!(::Circle.y)), Some(&5) );
72 /// assert_eq!( circle.field_(fp!(::Circle.radius)), Some(&8) );
73 ///
74 /// // Constructing the variant proxy is the only Option we have to handle here,
75 /// // instead of every access to the fields in the Circle variant being optional.
76 /// //
77 /// // For a more ergonomic alternative,
78 /// // you can look at the example for the `fields` method
79 /// let proxy=circle.field_(fp!(::Circle)).expect("Expected a circle");
80 /// assert_eq!( proxy.field_(fp!(x)), &3 );
81 /// assert_eq!( proxy.field_(fp!(y)), &5 );
82 /// assert_eq!( proxy.field_(fp!(radius)), &8 );
83 /// }
84 ///
85 /// #[derive(Structural)]
86 /// enum Shape{
87 /// Circle{x:u32,y:u32,radius:u32},
88 /// Square{x:u32,y:u32,width:u32},
89 /// }
90 ///
91 /// #[derive(Structural)]
92 /// # #[struc(no_trait)]
93 /// enum MoreShapes{
94 /// Circle{x:u32,y:u32,radius:u32},
95 /// Square{x:u32,y:u32,width:u32},
96 /// Rectangle{x:u32,y:u32,width:u32,height:u32},
97 /// }
98 ///
99 ///
100 /// ```
101 #[inline(always)]
102 fn field_<'a, P>(&'a self, path: P) -> NormalizeFieldsOut<Result<&'a P::Ty, P::Err>>
103 where
104 P: RevGetFieldImpl<'a, Self>,
105 Result<&'a P::Ty, P::Err>: NormalizeFields,
106 {
107 path.rev_get_field(self).normalize_fields()
108 }
109
110 /// Gets references to multiple fields,determined by `path`.
111 ///
112 /// # Access many fields
113 ///
114 /// If you pass a `path` that references over 8 fields,this will return a
115 /// tuple of tuples(each nested tuple with 8 elements) instead of
116 /// a singly nested tuple.
117 ///
118 /// For examples accessing over 8 field look at the docs for the [`field_pat`] macro
119 ///
120 /// [`field_pat`]: ./macro.field_pat.html#the-structuralext-example
121 ///
122 /// # Example
123 ///
124 /// ```
125 /// use structural::{StructuralExt,fp,structural_alias};
126 ///
127 /// structural_alias!{
128 /// trait OddFields<A,B,C>{
129 /// 1:A,
130 /// 3:B,
131 /// 5:C,
132 /// }
133 /// }
134 ///
135 /// fn with_even(this:&impl OddFields<u32,u32,u32>){
136 /// assert_eq!( this.fields(fp!(1,3,5)), (&22,&44,&77) );
137 /// }
138 ///
139 /// fn main(){
140 /// with_even( &(0,22,0,44,0,77) );
141 /// with_even( &(0,22,0,44,0,77,0) );
142 /// with_even( &(0,22,0,44,0,77,0,0) );
143 /// with_even( &(0,22,0,44,0,77,0,0,0) );
144 /// }
145 ///
146 /// ```
147 ///
148 /// # Enum Example
149 ///
150 /// ```
151 /// use structural::{StructuralExt,Structural,fp};
152 ///
153 /// with_car( &Vehicle::Car{ name:"initial-c", km:9001 } );
154 /// with_car( &MoreVehicles::Car{ name:"initial-c", km:9001 } );
155 ///
156 /// fn with_car<T>(car:&T)
157 /// where
158 /// // `Vehicle_SI` was generated for Vehicle by the `Structural` derive.
159 /// T: Vehicle_SI
160 /// {
161 /// assert_eq!(
162 /// car.fields(fp!(::Car.name, ::Car.km)),
163 /// ( Some(&"initial-c"), Some(&9001) )
164 /// );
165 ///
166 /// // You can use `=>` to access multiple fields inside of a nested field(or a variant)
167 /// // this allows accessing multiple fields inside an enum variant without having to
168 /// // create an intermediate variant proxy
169 /// // (look at the next assert for what that looks like).
170 /// assert_eq!( car.fields(fp!(::Car=>name,km)), Some((&"initial-c",&9001)) );
171 ///
172 /// assert_eq!(
173 /// // This is equivalent to the field access in the previous assert
174 /// car.field_(fp!(::Car)).map(|vp| vp.fields(fp!(name,km)) ),
175 /// Some((&"initial-c",&9001))
176 /// );
177 ///
178 /// assert_eq!( car.cloned_fields(fp!(::Truck=>weight_kg,driven_km)), None);
179 /// }
180 ///
181 /// #[derive(Structural)]
182 /// enum Vehicle{
183 /// Car{name: &'static str, km:u32},
184 /// Truck{ weight_kg:u32, driven_km:u32 },
185 /// }
186 ///
187 /// #[derive(Structural)]
188 /// # #[struc(no_trait)]
189 /// enum MoreVehicles{
190 /// Car{name: &'static str, km:u32},
191 /// Truck{ weight_kg:u32, driven_km:u32 },
192 /// Boat,
193 /// }
194 ///
195 ///
196 /// ```
197 #[inline(always)]
198 fn fields<'a, P>(&'a self, path: P) -> RevGetMultiFieldOut<'a, P, Self>
199 where
200 P: RevGetMultiField<'a, Self>,
201 {
202 path.rev_get_multi_field(self)
203 }
204
205 /// Gets clones of multiple fields,determined by `path`.
206 ///
207 /// # Access many fields
208 ///
209 /// If you pass a `path` that references over 8 fields,this will return a
210 /// tuple of tuples(each nested tuple with 8 elements) instead of
211 /// a singly nested tuple.
212 ///
213 /// For examples accessing over 8 field look at the docs for the [`field_pat`] macro
214 ///
215 /// [`field_pat`]: ./macro.field_pat.html#the-structuralext-example
216 ///
217 /// # Example
218 ///
219 /// This example also uses the reexported `IntoArray` trait,
220 /// which allows converting homogeneous tuples to arrays,
221 /// in this case it's used to iterate over the fields.
222 ///
223 /// ```
224 /// use structural::{StructuralExt,Structural,fp,make_struct};
225 /// use structural::reexports::IntoArray;
226 ///
227 /// // The `Fruits_SI` trait was declared by the `Structural` derive on `Fruits`.
228 /// fn total_fruit_count(fruits:&dyn Fruits_SI)->u32{
229 /// fruits
230 /// .cloned_fields(fp!( apples, oranges, tangerines, tomatoes ))
231 /// .into_array()
232 /// .iter()
233 /// .sum()
234 /// }
235 ///
236 /// {
237 /// let fruits=Fruits{
238 /// apples:1,
239 /// oranges:2,
240 /// tangerines:3,
241 /// tomatoes:5,
242 /// };
243 ///
244 /// assert_eq!( total_fruit_count(&fruits), 11 );
245 /// }
246 ///
247 /// {
248 /// let fruits=make_struct!{
249 /// apples:8,
250 /// oranges:13,
251 /// tangerines:21,
252 /// tomatoes:34,
253 /// };
254 ///
255 /// assert_eq!( total_fruit_count(&fruits), 76 );
256 /// }
257 ///
258 /// #[derive(Structural)]
259 /// // We only get read access to the fields.
260 /// #[struc(public,access="ref")]
261 /// struct Fruits{
262 /// apples:u32,
263 /// oranges:u32,
264 /// tangerines:u32,
265 /// tomatoes:u32,
266 /// }
267 ///
268 /// ```
269 ///
270 /// # Enum Example
271 ///
272 /// ```
273 /// use structural::{StructuralExt,Structural,fp};
274 ///
275 /// with_pc( &Device::Pc{ manufacturer:"dawn", year:2038 } );
276 /// with_pc( &MoreDevices::Pc{ manufacturer:"dawn", year:2038 } );
277 ///
278 /// fn with_pc<T>(pc:&T)
279 /// where
280 /// // `Device_SI` was generated for Device by the `Structural` derive.
281 /// T: Device_SI
282 /// {
283 /// assert_eq!(
284 /// pc.cloned_fields(fp!(::Pc.manufacturer, ::Pc.year)),
285 /// ( Some("dawn"), Some(2038) )
286 /// );
287 ///
288 /// // You can use `=>` to access multiple fields inside of a nested field(or a variant)
289 /// // this allows accessing multiple fields inside an enum variant without having to
290 /// // create an intermediate variant proxy
291 /// // (look at the next assert for what that looks like).
292 /// assert_eq!( pc.cloned_fields(fp!(::Pc=>manufacturer,year)), Some(("dawn",2038)) );
293 ///
294 /// assert_eq!(
295 /// // This is equivalent to the field access in the previous assert
296 /// pc.field_(fp!(::Pc)).map(|vp| vp.cloned_fields(fp!(manufacturer,year)) ),
297 /// Some(("dawn",2038))
298 /// );
299 ///
300 /// assert_eq!( pc.cloned_fields(fp!(::Phone=>number,charge)), None);
301 /// }
302 ///
303 /// #[derive(Structural)]
304 /// enum Device{
305 /// Pc{manufacturer: &'static str, year:u32},
306 /// Phone{number:&'static str,charge:u8},
307 /// }
308 ///
309 /// #[derive(Structural)]
310 /// # #[struc(no_trait)]
311 /// enum MoreDevices{
312 /// Pc{manufacturer: &'static str, year:u32},
313 /// Phone{number:&'static str,charge:u8},
314 /// Tablet,
315 /// }
316 ///
317 ///
318 /// ```
319 fn cloned_fields<'a, P>(&'a self, path: P) -> ClonedOut<RevGetMultiFieldOut<'a, P, Self>>
320 where
321 P: RevGetMultiField<'a, Self>,
322 RevGetMultiFieldOut<'a, P, Self>: Cloned,
323 {
324 path.rev_get_multi_field(self).cloned_()
325 }
326
327 /// Gets a mutable reference to a field,determined by `path`.
328 ///
329 /// # Example
330 ///
331 /// ```
332 /// use structural::{StructuralExt,fp,make_struct,Structural};
333 ///
334 /// #[derive(Structural)]
335 /// struct Human{
336 /// pub x:i32,
337 /// pub y:i32,
338 /// pub health:u32,
339 /// flags:u32,
340 /// }
341 ///
342 /// // The `Human_SI` trait was declared by the `Structural` derive on `Human`.
343 /// fn move_human( this:&mut dyn Human_SI, dx:i32, dy:i32 ){
344 /// *this.field_mut(fp!(x))+=dx;
345 /// *this.field_mut(fp!(y))+=dy;
346 /// }
347 ///
348 /// {
349 /// let mut entity=make_struct!{
350 /// x: 0,
351 /// y: 0,
352 /// health: 100,
353 /// };
354 /// move_human(&mut entity,-100,300);
355 /// assert_eq!( entity.fields(fp!(x,y,health)), (&-100,&300,&100) )
356 /// }
357 /// {
358 /// let mut entity=Human{
359 /// x: -1000,
360 /// y: 1000,
361 /// health: 1,
362 /// flags: 0b11111,
363 /// };
364 ///
365 /// move_human(&mut entity,500,-200);
366 ///
367 /// assert_eq!( entity.x, -500 );
368 /// assert_eq!( entity.y, 800 );
369 /// assert_eq!( entity.health, 1 );
370 /// assert_eq!( entity.flags, 0b11111 );
371 /// }
372 ///
373 /// ```
374 ///
375 /// # Enum Example
376 ///
377 /// ```
378 /// use structural::{StructuralExt,Structural,fp};
379 ///
380 /// with_soda( &mut Beverage::Soda{ ml:600, cents:400 } );
381 /// with_soda( &mut MoreBeverages::Soda{ ml:600, cents:400 } );
382 ///
383 /// fn with_soda<T>(soda:&mut T)
384 /// where
385 /// // `Beverage_SI` was generated for Beverage by the `Structural` derive.
386 /// T: Beverage_SI
387 /// {
388 /// assert_eq!( soda.field_mut(fp!(::Soda.ml)), Some(&mut 600) );
389 /// assert_eq!( soda.field_mut(fp!(::Soda.cents)), Some(&mut 400) );
390 ///
391 /// // Constructing the variant proxy is the only Option we have to handle here,
392 /// // instead of every access to the fields in the Soda variant being optional.
393 /// let proxy=soda.field_mut(fp!(::Soda)).expect("Expected a soda");
394 /// assert_eq!( proxy.field_mut(fp!(ml)), &mut 600 );
395 /// assert_eq!( proxy.field_mut(fp!(cents)), &mut 400 );
396 /// }
397 ///
398 /// #[derive(Structural)]
399 /// enum Beverage{
400 /// Soda{ ml:u32, cents:u32 },
401 /// Water,
402 /// }
403 ///
404 /// #[derive(Structural)]
405 /// # #[struc(no_trait)]
406 /// enum MoreBeverages{
407 /// Soda{ ml:u32, cents:u32 },
408 /// Water,
409 /// Beer,
410 /// }
411 ///
412 ///
413 /// ```
414 #[inline(always)]
415 fn field_mut<'a, P>(&'a mut self, path: P) -> NormalizeFieldsOut<Result<&'a mut P::Ty, P::Err>>
416 where
417 P: RevGetFieldMutImpl<'a, Self>,
418 Result<&'a mut P::Ty, P::Err>: NormalizeFields,
419 {
420 path.rev_get_field_mut(self).normalize_fields()
421 }
422
423 /// Gets mutable references to multiple fields,determined by `path`.
424 ///
425 /// # Access many fields
426 ///
427 /// If you pass a `path` that references over 8 fields,this will return a
428 /// tuple of tuples(each nested tuple with 8 elements) instead of
429 /// a singly nested tuple.
430 ///
431 /// For examples accessing over 8 field look at the docs for the [`field_pat`] macro
432 ///
433 /// [`field_pat`]: ./macro.field_pat.html#the-structuralext-example
434 ///
435 /// # Example
436 ///
437 /// ```
438 /// use structural::{
439 /// StructuralExt,GetFieldMut,GetFieldType,Structural,
440 /// fp,field_path_aliases,
441 /// };
442 ///
443 /// field_path_aliases!{
444 /// mod names{x,y}
445 /// }
446 ///
447 /// fn swap_coordinates<T,U>(this:&mut T)
448 /// where
449 /// T:GetFieldMut<names::x,Ty=U>,
450 /// T:GetFieldMut<names::y,Ty=U>,
451 /// {
452 /// let (x,y)=this.fields_mut(fp!(x,y));
453 /// std::mem::swap(x,y);
454 /// }
455 ///
456 /// {
457 /// let mut this=Point2D{ x:100, y:300 };
458 /// swap_coordinates(&mut this);
459 /// assert_eq!( this.x, 300 );
460 /// assert_eq!( this.y, 100 );
461 /// }
462 ///
463 /// {
464 /// let mut this=Point3D{ x:30, y:0, z:500 };
465 /// swap_coordinates(&mut this);
466 /// assert_eq!( this.x, 0 );
467 /// assert_eq!( this.y, 30 );
468 /// assert_eq!( this.z, 500 );
469 /// }
470 ///
471 /// #[derive(Structural)]
472 /// struct Point2D<T>{
473 /// pub x:T,
474 /// pub y:T,
475 /// }
476 ///
477 /// #[derive(Structural)]
478 /// struct Point3D<T>{
479 /// pub x:T,
480 /// pub y:T,
481 /// pub z:T,
482 /// }
483 ///
484 ///
485 /// ```
486 ///
487 /// # Example
488 ///
489 /// An example of how this method does not allow multiple mutable borrows
490 /// of the same field.
491 ///
492 /// ```compile_fail
493 /// use structural::{StructuralExt,fp};
494 ///
495 /// let mut tup=(1,1,2,3,5,8);
496 ///
497 /// let _=tup.fields_mut(fp!(4,4));
498 ///
499 /// ```
500 ///
501 /// # Enum Example
502 ///
503 /// ```
504 /// use structural::{StructuralExt,Structural,fp};
505 ///
506 /// with_book( &mut Medium::Book{ pages:500, title:"Dracular" } );
507 /// with_book( &mut MoreMedia::Book{ pages:500, title:"Dracular" } );
508 ///
509 /// fn with_book<T>(book:&mut T)
510 /// where
511 /// // `Medium_SI` was generated for Medium by the `Structural` derive.
512 /// T: Medium_SI
513 /// {
514 /// assert_eq!(
515 /// book.fields_mut(fp!(::Book.pages, ::Book.title)),
516 /// ( Some(&mut 500), Some(&mut "Dracular") )
517 /// );
518 ///
519 /// // You can use `=>` to access multiple fields inside of a nested field(or a variant)
520 /// // this allows accessing multiple fields inside an enum variant without having to
521 /// // create an intermediate variant proxy
522 /// // (look at the next assert for what that looks like).
523 /// assert_eq!(
524 /// book.fields_mut(fp!(::Book=>pages,title)),
525 /// Some((&mut 500,&mut "Dracular")),
526 /// );
527 ///
528 /// assert_eq!(
529 /// // This is equivalent to the field access in the previous assert
530 /// book.field_mut(fp!(::Book)).map(|vp| vp.fields_mut(fp!(pages,title)) ),
531 /// Some((&mut 500,&mut "Dracular"))
532 /// );
533 ///
534 /// assert_eq!( book.fields_mut(fp!(::Comic=>artist,in_color)), None);
535 /// }
536 ///
537 /// #[derive(Structural)]
538 /// enum Medium{
539 /// Book{ pages:u32, title:&'static str },
540 /// Comic{artist:&'static str,in_color:bool},
541 /// }
542 ///
543 /// #[derive(Structural)]
544 /// # #[struc(no_trait)]
545 /// enum MoreMedia{
546 /// Book{ pages:u32, title:&'static str },
547 /// Comic{artist:&'static str,in_color:bool},
548 /// Television,
549 /// }
550 ///
551 /// ```
552 #[inline(always)]
553 fn fields_mut<'a, P>(&'a mut self, path: P) -> RevGetMultiFieldMutOut<'a, P, Self>
554 where
555 P: RevGetMultiFieldMut<'a, Self>,
556 {
557 path.rev_get_multi_field_mut(self)
558 }
559
560 /// Converts ´self´ into a field,determined by `path`.
561 ///
562 /// # Example
563 ///
564 /// ```
565 /// use structural::{StructuralExt,Structural,fp};
566 ///
567 ///
568 /// #[derive(Structural,Clone)]
569 /// #[struc(public,access="move")]
570 /// struct Tupled<T>(T,T,T,T);
571 ///
572 /// // The `Tupled_SI` trait was declared by the `Structural` derive on `Tupled`.
573 /// fn pick_index<T>(this:impl Tupled_SI<T>,which_one:u32)->T{
574 /// match which_one % 4 {
575 /// 0=>this.into_field(fp!(0)),
576 /// 1=>this.into_field(fp!(1)),
577 /// 2=>this.into_field(fp!(2)),
578 /// _=>this.into_field(fp!(3)),
579 /// }
580 /// }
581 ///
582 /// {
583 /// let tup=Tupled(13,21,34,55);
584 ///
585 /// assert_eq!( pick_index(tup.clone(),0), 13 );
586 /// assert_eq!( pick_index(tup.clone(),1), 21 );
587 /// assert_eq!( pick_index(tup.clone(),2), 34 );
588 /// assert_eq!( pick_index(tup ,3), 55 );
589 /// }
590 ///
591 /// {
592 /// let array=[13,21,34,55];
593 ///
594 /// assert_eq!( pick_index(array.clone(),0), 13 );
595 /// assert_eq!( pick_index(array.clone(),1), 21 );
596 /// assert_eq!( pick_index(array.clone(),2), 34 );
597 /// assert_eq!( pick_index(array ,3), 55 );
598 /// }
599 ///
600 /// ```
601 ///
602 /// # Enum Example
603 ///
604 /// ```
605 /// use structural::{StructuralExt,Structural,fp};
606 ///
607 /// with_table( &Furniture::Table{ height_cm:101, width_cm:333 } );
608 /// with_table( &MoreFurniture::Table{ height_cm:101, width_cm:333 } );
609 ///
610 /// fn with_table<T>(table:&T)
611 /// where
612 /// // `Furniture_SI` was generated for Furniture by the `Structural` derive.
613 /// T: Furniture_SI + Clone
614 /// {
615 /// assert_eq!( table.clone().into_field(fp!(::Table.height_cm)), Some(101) );
616 /// assert_eq!( table.clone().into_field(fp!(::Table.width_cm)), Some(333) );
617 ///
618 /// // Constructing the variant proxy is the only Option we have to handle here,
619 /// // instead of every access to the fields in the Table variant being optional.
620 /// let proxy=table.clone().into_field(fp!(::Table)).expect("Expected a table");
621 /// assert_eq!( proxy.clone().into_field(fp!(height_cm)), 101 );
622 /// assert_eq!( proxy.clone().into_field(fp!(width_cm)), 333 );
623 /// }
624 ///
625 /// #[derive(Structural,Clone)]
626 /// enum Furniture{
627 /// Table{ height_cm:u32, width_cm:u32 },
628 /// Chair,
629 /// }
630 ///
631 /// #[derive(Structural,Clone)]
632 /// # #[struc(no_trait)]
633 /// enum MoreFurniture{
634 /// Table{ height_cm:u32, width_cm:u32 },
635 /// Chair,
636 /// Sofa,
637 /// }
638 ///
639 ///
640 /// ```
641 #[inline(always)]
642 fn into_field<P>(self, path: P) -> NormalizeFieldsOut<Result<P::Ty, P::Err>>
643 where
644 P: RevIntoFieldImpl<Self>,
645 P::Ty: Sized,
646 Result<P::Ty, P::Err>: NormalizeFields,
647 Self: Sized,
648 {
649 path.rev_into_field(self).normalize_fields()
650 }
651
652 /// Converts `self` into multiple fields by value.
653 ///
654 /// # Access many fields
655 ///
656 /// If you pass a `path` that references over 8 fields,this will return a
657 /// tuple of tuples(each nested tuple with 8 elements) instead of
658 /// a singly nested tuple.
659 ///
660 /// For examples accessing over 8 field look at the docs for the [`field_pat`] macro
661 ///
662 /// [`field_pat`]: ./macro.field_pat.html#the-structuralext-example
663 ///
664 /// # Valid Paths
665 ///
666 /// As opposed to the other multiple fields accessor methods,
667 /// this method only accepts field paths that refer to
668 /// multiple non-nested fields inside some value (possibly a nested field itself).
669 ///
670 /// <span id="valid_into_field_paths"></span>
671 ///
672 /// Examples of accepted field paths:
673 ///
674 /// - `fp!(a, b, c)`:
675 /// Accesses the `a`,`b`,and `c` fields.
676 ///
677 /// - `fp!(a.b.c=> d, e, f)`:
678 /// Accesses the `d`,`e`,and `f` fields inside the `a.b.c` field.
679 ///
680 /// - `fp!(::Foo=> bar, baz)`:
681 /// Accesses the `bar` and `baz` field in the `Foo` variant.
682 ///
683 /// Examples of rejected field paths(accepted in other methods):
684 ///
685 /// - `fp!(a.b, c)`
686 ///
687 /// - `fp!(a.b, c.d)`
688 ///
689 /// - `fp!(::Bar=> a.b, c.d)`
690 ///
691 /// # Struct Example
692 ///
693 /// ```rust
694 /// use structural::{StructuralExt,fp,make_struct};
695 /// use structural::for_examples::{Struct2, Struct2_SI, Struct3};
696 ///
697 /// assert_eq!(
698 /// into_struct2(Struct3{ foo:Some("13".to_string()), bar: 21, baz: 34}),
699 /// Struct2{ foo:Some("13".to_string()), bar: 21 }
700 /// );
701 ///
702 /// {
703 /// let value=Struct2{ foo:Some(vec![55, 89]), bar: 144 };
704 /// assert_eq!( into_struct2(value.clone()), value );
705 /// }
706 ///
707 /// assert_eq!(
708 /// into_struct2(make_struct!{
709 /// foo: None::<()>,
710 /// bar: 233,
711 /// baz: false,
712 /// qux: "hello".to_string()
713 /// }),
714 /// Struct2{ foo:None, bar: 233 }
715 /// );
716 ///
717 /// // `Struct2_SI` was declared by the `Structural` derive on `Struct2`,
718 /// // aliasing the accessor traits that `Struct2` implements.
719 /// fn into_struct2<T,U>(this: impl Struct2_SI<T,U>)->Struct2<T,U>{
720 /// let (foo, bar)=this.into_fields(fp!(foo, bar));
721 /// Struct2{foo, bar}
722 /// }
723 ///
724 /// ```
725 ///
726 /// # Enum Example
727 ///
728 /// ```rust
729 /// use structural::{StructuralExt,fp};
730 /// use structural::for_examples::{Enum1, Enum1_SI, Enum2, Enum3};
731 ///
732 /// use std::cmp::Ordering;
733 ///
734 /// assert_eq!( into_enum1(Enum1::Foo(3, 5)), Some(Enum1::Foo(3, 5)) );
735 ///
736 /// assert_eq!( into_enum1(Enum2::Foo(8, 13)), Some(Enum1::Foo(8, 13)) );
737 /// assert_eq!( into_enum1(Enum2::Bar(Ordering::Less, None)), None );
738 ///
739 /// assert_eq!( into_enum1(Enum3::Foo(21, 34)), Some(Enum1::Foo(21, 34)) );
740 /// assert_eq!( into_enum1(Enum3::Bar(Ordering::Less, None)), None );
741 /// assert_eq!( into_enum1(Enum3::Baz { foom: "whoop"}), None );
742 ///
743 /// // `Enum1_SI` was declared by the `Structural` derive on `Enum1`,
744 /// // aliasing the accessor traits that `Enum1` implements.
745 /// fn into_enum1(this: impl Enum1_SI)-> Option<Enum1> {
746 /// this.into_fields(fp!(::Foo=>0,1))
747 /// .map(|(a,b)| Enum1::Foo(a,b) )
748 /// }
749 ///
750 /// ```
751 ///
752 #[inline(always)]
753 fn into_fields<P>(self, path: P) -> RevIntoMultiFieldOut<P, Self>
754 where
755 P: RevIntoMultiField<Self>,
756 Self: Sized,
757 {
758 path.rev_into_multi_field(self)
759 }
760
761 /// Checks whether an enum is a particular variant.
762 ///
763 /// # Example
764 ///
765 /// ```
766 /// use structural::{StructuralExt,Structural,fp};
767 ///
768 /// check_colors( &Color::Red, &Color::Blue, &Color::Green );
769 /// check_colors( &ColorPlus::Red, &ColorPlus::Blue, &ColorPlus::Green );
770 ///
771 /// fn check_colors<T>( red:&T, blue:&T, green:&T )
772 /// where
773 /// // `Color_SI` was declared by the `Structural` derive on `Color`,
774 /// // aliasing the accessor traits that `Color` implements.
775 /// T: Color_SI
776 /// {
777 /// assert!( red.is_variant(fp!(Red)) );
778 /// assert!( !red.is_variant(fp!(Blue)) );
779 /// assert!( !red.is_variant(fp!(Green)) );
780 ///
781 /// assert!( !blue.is_variant(fp!(Red)) );
782 /// assert!( blue.is_variant(fp!(Blue)) );
783 /// assert!( !blue.is_variant(fp!(Green)) );
784 ///
785 /// assert!( !green.is_variant(fp!(Red)) );
786 /// assert!( !green.is_variant(fp!(Blue)) );
787 /// assert!( green.is_variant(fp!(Green)) );
788 /// }
789 ///
790 /// #[derive(Structural)]
791 /// enum Color{
792 /// Red,
793 /// Blue,
794 /// Green,
795 /// }
796 ///
797 /// #[derive(Structural)]
798 /// # #[struc(no_trait)]
799 /// enum ColorPlus{
800 /// Red,
801 /// Blue,
802 /// Green,
803 /// Teal,
804 /// White,
805 /// Gray,
806 /// Black,
807 /// }
808 ///
809 ///
810 /// ```
811 #[inline(always)]
812 fn is_variant<P>(&self, _path: P) -> bool
813 where
814 P: IsTStr,
815 Self: IsVariant<P>,
816 {
817 IsVariant::is_variant_(self, _path)
818 }
819
820 /// Converts this into another structural type using `IntoStructural`.
821 ///
822 /// # Struct Example
823 ///
824 /// ```rust
825 /// use structural::{
826 /// Structural, StructuralExt, fp, make_struct,
827 /// };
828 ///
829 /// assert_eq!( Foo(55, 89, 144, 233).into_struc::<[_;3]>(), [55, 89, 144] );
830 ///
831 /// assert_eq!(
832 /// make_struct!{x:"foo", y:"bar", z:"baz", w:"what"}.into_struc::<Point<_>>(),
833 /// Point{x:"foo", y:"bar", z:"baz"}
834 /// );
835 ///
836 /// #[derive(Debug,Structural,PartialEq)]
837 /// # #[struc(no_trait)]
838 /// struct Foo(pub u8, pub u8, pub u8, pub u8);
839 ///
840 /// #[derive(Debug,Structural,PartialEq)]
841 /// struct Point<T>{
842 /// pub x: T,
843 /// pub y: T,
844 /// pub z: T,
845 /// }
846 ///
847 /// // This macro also implement TryFromStructural for Point
848 /// structural::z_impl_from_structural!{
849 /// impl[F, T] FromStructural<F> for Point<T>
850 /// where[
851 /// // `Point_SI` was generated for `Point` by the Structural derive.
852 /// F: Point_SI<T>,
853 /// ]{
854 /// fn from_structural(this){
855 /// let (x,y,z) = this.into_fields(fp!(x, y, z));
856 /// Self{x,y,z}
857 /// }
858 /// }
859 /// }
860 ///
861 /// ```
862 ///
863 /// # Enum example
864 ///
865 /// ```rust
866 /// use structural::{
867 /// for_examples::ResultLike,
868 /// Structural, StructuralExt, switch,
869 /// };
870 ///
871 /// assert_eq!( ResultLike::<_,()>::Ok (300).into_struc::<ResultV>(), ResultV::Ok );
872 /// assert_eq!( ResultLike::<(),_>::Err(300).into_struc::<ResultV>(), ResultV::Err );
873 ///
874 /// assert_eq!( Ok::<_,()>(300).into_struc::<ResultV>(), ResultV::Ok );
875 /// assert_eq!( Err::<(),_>(300).into_struc::<ResultV>(), ResultV::Err );
876 ///
877 /// #[derive(Debug,Structural,PartialEq)]
878 /// enum ResultV{
879 /// Ok,
880 /// Err,
881 /// }
882 ///
883 /// // This macro also implement TryFromStructural for ResultV
884 /// structural::z_impl_from_structural!{
885 /// impl[F] FromStructural<F> for ResultV
886 /// where[
887 /// // `ResultV_ESI` was generated for `Point` by the Structural derive.
888 /// F: ResultV_ESI
889 /// ]{
890 /// fn from_structural(this){
891 /// switch!{this;
892 /// Ok => ResultV::Ok,
893 /// Err => ResultV::Err,
894 /// }
895 /// }
896 /// }
897 /// }
898 ///
899 /// ```
900 ///
901 fn into_struc<U>(self) -> U
902 where
903 Self: IntoStructural<U>,
904 {
905 self.into_structural()
906 }
907
908 /// Performs a fallible conversion into another structural type using `TryIntoStructural`.
909 ///
910 /// # Enum example
911 ///
912 /// ```rust
913 /// use structural::{
914 /// convert::{EmptyTryFromError, TryFromError},
915 /// for_examples::ResultLike,
916 /// Structural, StructuralExt, switch,
917 /// };
918 ///
919 /// assert_eq!( Shapes::Rectangle.try_into_struc::<Shapes>(), Ok(Shapes::Rectangle) );
920 /// assert_eq!( Shapes::Circle.try_into_struc::<Shapes>() , Ok(Shapes::Circle) );
921 ///
922 /// assert_eq!( MoreShapes::Rectangle.try_into_struc::<Shapes>(), Ok(Shapes::Rectangle) );
923 /// assert_eq!( MoreShapes::Circle.try_into_struc::<Shapes>() , Ok(Shapes::Circle) );
924 /// assert_eq!(
925 /// MoreShapes::Hexagon.try_into_struc::<Shapes>(),
926 /// Err(TryFromError::with_empty_error(MoreShapes::Hexagon)),
927 /// );
928 ///
929 /// #[derive(Debug,Structural,PartialEq)]
930 /// enum Shapes{
931 /// Rectangle,
932 /// Circle,
933 /// }
934 ///
935 /// #[derive(Debug,Structural,PartialEq)]
936 /// enum MoreShapes{
937 /// Rectangle,
938 /// Circle,
939 /// Hexagon,
940 /// }
941 ///
942 /// // This macro implements FromStructural in terms of TryFromStructural,
943 /// structural::z_impl_try_from_structural_for_enum!{
944 /// impl[F] TryFromStructural<F> for Shapes
945 /// where[ F: Shapes_SI, ]
946 /// {
947 /// type Error = EmptyTryFromError;
948 ///
949 /// fn try_from_structural(this){
950 /// switch! {this;
951 /// Rectangle => Ok(Self::Rectangle),
952 /// Circle => Ok(Self::Circle),
953 /// _ => Err(TryFromError::with_empty_error(this)),
954 /// }
955 /// }
956 /// }
957 ///
958 /// // `Shapes_ESI` was generated by the `Structural` derive for `Shapes`
959 /// // aliasing its accessor trait impls,
960 /// // and requires `F` to only have the `Rectangle` and `Circle` variants.
961 /// FromStructural
962 /// where[ F: Shapes_ESI, ]
963 /// }
964 ///
965 /// ```
966 ///
967 fn try_into_struc<U>(self) -> Result<U, TryFromError<Self, Self::Error>>
968 where
969 Self: TryIntoStructural<U>,
970 {
971 self.try_into_structural()
972 }
973}
974
975impl<T: ?Sized> StructuralExt for T {}