structural/macros/
tstr_macros.rs

1/**
2Declares type aliases for [`TStr<_>`(type-level string)](./struct.TStr.html).
3
4# Variants
5
6### Inline
7
8Where the aliases are declared at the scope that the macro is invoked.
9
10This variant cannot be invoked within functions.
11
12Small example:
13```rust
14use structural::tstr_aliases;
15
16tstr_aliases!{
17    a, // Declares a type alias `a` with the "a" TStr.
18    b="b", // Declares a type alias `b` with the "b" TStr.
19}
20# fn main(){}
21```
22### Module
23
24Where the aliases are declared inside a nested module.
25
26This variant can be invoked within functions.
27
28Small example:
29```rust
30use structural::tstr_aliases;
31
32fn hello(){
33    tstr_aliases!{
34        mod hello{
35            a,
36            b="b",
37        }
38    }
39}
40```
41
42# Example
43
44Writing a function that takes a `::Foo.bar` field.
45
46You can use `tstr_aliases` or `TS` to manually declare
47variant field accessor trait bounds.
48
49```
50use structural::{
51    field::GetVariantField,
52    StructuralExt,Structural,
53    tstr_aliases,fp,
54};
55
56tstr_aliases!{
57    mod strs{
58        Foo,
59        bar,
60    }
61}
62
63fn takes_enum( enum_:&dyn GetVariantField< strs::Foo, strs::bar, Ty= u32 > )-> Option<u32> {
64    enum_.field_(fp!(::Foo.bar)).cloned()
65}
66
67#[derive(Structural)]
68enum Baz{
69    Foo{ bar:u32 },
70    Bar,
71}
72
73fn main(){
74
75    assert_eq!( takes_enum(&Baz::Foo{bar:0}), Some(0) );
76    assert_eq!( takes_enum(&Baz::Foo{bar:5}), Some(5) );
77    assert_eq!( takes_enum(&Baz::Bar), None );
78
79}
80
81```
82
83
84*/
85#[macro_export]
86macro_rules! tstr_aliases {
87    (
88        $(#[$attr:meta])*
89        $vis:vis mod $mod_name:ident{
90            $($mod_contents:tt)*
91        }
92    ) => (
93        /// Type aliases for [`TStr`](./struct.TStr.html)
94        /// (from the structural crate).
95        ///
96        /// `TStr` values can be constructed with the NEW associated constant.
97        ///
98        /// The source code for this module can only be accessed from
99        /// the type aliases.<br>
100        /// As of writing this documentation,`cargo doc` links
101        /// to the inplementation of the `field_path_aliases` macro
102        /// instead of where this module is declared.
103        #[allow(non_camel_case_types)]
104        #[allow(non_upper_case_globals)]
105        #[allow(unused_imports)]
106        $(#[$attr])*
107        $vis mod $mod_name{
108            $crate::_tstring_aliases_impl!{
109                $($mod_contents)*
110            }
111        }
112    );
113    (
114        $($macro_params:tt)*
115    ) => (
116        $crate::_tstring_aliases_impl!{
117            $($macro_params)*
118        }
119    );
120}
121
122////////////////////////////////////////////////////////////////////////////////
123
124/**
125
126For getting the type of a [`TStr<_>` (type-level string)](./struct.TStr.html).
127
128You can also use [`tstr_aliases`](./macro.tstr_aliases.html)
129to declare one or more aliases for type-level strings.
130
131### Inputs
132
133This has the same syntax as the [`ts`](./macro.ts.html) macro,
134a single identifier,string literal, or integer.
135
136
137Small Example:
138
139```rust
140use structural::TS;
141
142type Foo=TS!("foo");
143
144type Bar=TS!(foo); // Equivalent to `TS!("foo")`
145
146type Baz=TS!(100); // Equivalent to `TS!("100")`
147
148```
149
150# Example
151
152This example demonstrates how `TStr` can be used to manually bound a
153type parameter with the `*VariantField*` traits,to access a variant field.
154
155```rust
156use structural::{StructuralExt,FP,Structural,TS,ts};
157use structural::{GetFieldType, GetVariantFieldType, IntoVariantFieldMut, VariantField};
158
159// `GetFieldType<This,FP!(::Ok.0)>` can also be written as
160// `GetVariantFieldType<This,TS!(Ok),TS!(0)>`.
161//
162// `GetVariantFieldType` is useful in generic contexts where
163// the name of the variant is taken  separately from the name of the field.
164fn into_ok<This>(this: This)->Option<GetFieldType<This,FP!(::Ok.0)>>
165where
166    This: IntoVariantFieldMut<TS!(Ok),TS!(0)>
167{
168    // Equivalent to: `this.into_field(fp!(::Ok.0))`
169    this.into_field(VariantField::new(ts!("Ok"), ts!("0")))
170}
171
172#[derive(Structural)]
173# #[struc(no_trait)]
174enum ResultLike<T,E>{
175    Ok(T),
176    Err(E),
177}
178
179assert_eq!( into_ok(ResultLike::<_,()>::Ok(99)), Some(99));
180assert_eq!( into_ok(ResultLike::<(),_>::Err(99)), None);
181
182assert_eq!( into_ok(Result::<_,()>::Ok(99)), Some(99));
183assert_eq!( into_ok(Result::<(),_>::Err(99)), None);
184
185
186```
187
188
189# Example
190
191This example uses the `TS` macro to access a single non-nested field,
192instead of the [`FP`](./macro.FP.html) or [`fp`](./macro.fp.html) macros.
193
194```rust
195use structural::{GetField,StructuralExt,Structural,FP,TS};
196
197fn main(){
198    let phone=CellPhone{
199        memory: Bytes{ bytes:64_000_000_000 },
200        charge: Charge{ percent:50 },
201    };
202    assert_eq!( get_charge(&phone).percent, 50 );
203
204    let battery=Battery{
205        charge: Charge{ percent:70 },
206    };
207    assert_eq!( get_charge(&battery).percent, 70 );
208}
209
210type charge_TStr=TS!(charge);
211
212// An `FP!(identifier)` is the same type as `TS!(identifier)`,
213// but because it's more flexible it's used for field paths by default.
214// Eg:You can write `GetFieldType<FooEnum, FP!(::Foo.bar)>` with `FP` but not with `TS`.
215//
216// `TS` always produces the `TStr` type,
217// while FP produces different types depending on the input.
218fn get_charge( this:&dyn GetField<FP!(charge), Ty=Charge> )-> Charge {
219    this.field_(charge_TStr::NEW).clone()
220}
221
222#[derive(Structural)]
223struct CellPhone{
224    pub memory: Bytes,
225    pub charge: Charge,
226}
227
228#[derive(Structural)]
229struct Battery{
230    pub charge: Charge,
231}
232
233#[derive(Debug,Copy,Clone)]
234struct Bytes{
235    bytes: u64,
236}
237
238#[derive(Debug,Copy,Clone)]
239struct Charge{
240    percent: u8,
241}
242
243
244```
245
246
247
248*/
249#[macro_export]
250macro_rules! TS {
251    (0) => {
252        $crate::path::string_aliases::str_0
253    };
254    (1) => {
255        $crate::path::string_aliases::str_1
256    };
257    (2) => {
258        $crate::path::string_aliases::str_2
259    };
260    (3) => {
261        $crate::path::string_aliases::str_3
262    };
263    (4) => {
264        $crate::path::string_aliases::str_4
265    };
266    (5) => {
267        $crate::path::string_aliases::str_5
268    };
269    (6) => {
270        $crate::path::string_aliases::str_6
271    };
272    (7) => {
273        $crate::path::string_aliases::str_7
274    };
275    (8) => {
276        $crate::path::string_aliases::str_8
277    };
278    (9) => {
279        $crate::path::string_aliases::str_9
280    };
281    (_) => {
282        $crate::path::string_aliases::str_underscore
283    };
284    ( $literal:literal ) => {
285        $crate::_TStr_from_literal!($literal)
286    };
287    ($ident:ident) => {
288        $crate::_TStr_from_ident!($ident)
289    };
290}
291
292//////////
293
294#[doc(hidden)]
295#[macro_export]
296#[cfg(all(feature = "use_const_str", not(feature = "disable_const_str")))]
297macro_rules! _TStr_from_literal {
298    ( $literal:literal )=>{
299        $crate::_TStr_lit_impl_!($literal)
300
301        // Unfortunately,this errors when used in trait bounds for some reason.
302        //
303        // $crate::TStr<$crate::__TS<{
304        //     $crate::const_generic_utils::StrFromLiteral::new($literal,stringify!($literal))
305        //         .str_from_lit()
306        // }>>
307    };
308    // Using `:expr` because `:literal` doesn't accept `stringify!(foo)` as a parameter
309    (@str $literal:expr ) => {
310        $crate::TStr<$crate::__TS<$literal>>
311    };
312}
313
314#[doc(hidden)]
315#[macro_export]
316#[cfg(any(not(feature = "use_const_str"), feature = "disable_const_str"))]
317macro_rules! _TStr_from_literal {
318    ($(@str)? $literal:literal ) => {
319        $crate::_TStr_lit_impl_!($literal)
320    };
321}
322
323//////////
324
325#[doc(hidden)]
326#[macro_export]
327#[cfg(all(feature = "use_const_str", not(feature = "disable_const_str")))]
328macro_rules! _TStr_from_ident {
329    ( $literal:ident ) => {
330        $crate::_TStr_ident_impl_!($literal)
331        // $crate::_TStr_from_literal!(@str stringify!($literal))
332    };
333}
334
335#[doc(hidden)]
336#[macro_export]
337#[cfg(any(not(feature = "use_const_str"), feature = "disable_const_str"))]
338macro_rules! _TStr_from_ident {
339    ( $literal:ident ) => {
340        $crate::_TStr_ident_impl_!($literal)
341    };
342}
343
344//////////
345
346/**
347Constructs a
348[`TStr`](./struct.TStr.html)
349value,a type-level string used for identifiers in field paths.
350
351# Input
352
353This macro can take any one of these as input:
354
355- A string literal,eg: `ts!("bar baz")`
356
357- An integer,eg: `ts!(99)` (equivalent to `ts!("99")`)
358
359- An identifier,eg: `ts!(foo)` (equivalent to `ts!("foo")`)
360
361# Example
362
363Here are examples of constructing field paths using this macro,
364they are paired up with the `fp` macro for comparison.
365
366```
367use structural::{StructuralExt, Structural, ts, fp, field_path_aliases};
368use structural::enums::VariantProxy;
369use structural::path::{
370    VariantField, VariantName, NestedFieldPath, FieldPathSet, NestedFieldPathSet,
371};
372
373let tuple=( 3, 5, (8,80,800), (13,21,(34,55)), Some(('a','b','c')) );
374
375////////////////////////////////////////////////////////////////////
376////               Constructing `NestedFieldPath`
377
378let path_0=ts!(0);
379assert_eq!( tuple.field_(path_0), &3 );
380assert_eq!( tuple.field_(fp!(0)), &3 );
381
382let path_1=ts!(1);
383assert_eq!( tuple.field_(path_1), &5 );
384assert_eq!( tuple.field_(fp!(1)), &5 );
385
386let path_2_0=NestedFieldPath::many((ts!(2), ts!(0)));
387assert_eq!( tuple.field_(path_2_0), &8 );
388assert_eq!( tuple.field_(fp!(2.0)), &8 );
389
390let path_2_1=NestedFieldPath::many((ts!(2), ts!(1)));
391assert_eq!( tuple.field_(path_2_1), &80 );
392assert_eq!( tuple.field_(fp!(2.1)), &80 );
393
394let path_2_2=NestedFieldPath::many((ts!(2), ts!(2)));
395assert_eq!( tuple.field_(path_2_2), &800 );
396assert_eq!( tuple.field_(fp!(2.2)), &800 );
397
398let path_3_2_0=NestedFieldPath::many((ts!(3), ts!(2), ts!(0)));
399assert_eq!( tuple.field_(path_3_2_0), &34 );
400assert_eq!( tuple.field_(fp!(3.2.0)), &34 );
401
402let path_3_2_1=NestedFieldPath::many((ts!(3), ts!(2), ts!(1)));
403assert_eq!( tuple.field_(path_3_2_1), &55 );
404assert_eq!( tuple.field_(fp!(3.2.1)), &55 );
405
406////////////////////////////////////////////////////////////////////
407////            Constructing VariantName
408
409#[derive(Debug,Structural,PartialEq)]
410# #[struc(no_trait)]
411enum Binary{
412    Left(u32,u32),
413    Right{
414        c: char,
415        is_true: bool,
416    },
417}
418
419let left=Binary::Left(3,5);
420let right=Binary::Right{c: 'a', is_true: false};
421
422field_path_aliases!{
423    mod paths{Left,Right}
424}
425
426let _:&VariantProxy<Binary, paths::Left>=
427    left.field_(VariantName::new(ts!(Left))).unwrap();
428let _:&VariantProxy<Binary, paths::Left>=
429    left.field_(fp!(::Left)).unwrap();
430
431assert_eq!( left.field_(VariantName::new(ts!(Right))), None);
432assert_eq!( left.field_(fp!(::Right)), None);
433
434
435let _:&VariantProxy<Binary, paths::Right>=
436    right.field_(VariantName::new(ts!(Right))).unwrap();
437let _:&VariantProxy<Binary, paths::Right>=
438    right.field_(fp!(::Right)).unwrap();
439
440assert_eq!( right.field_(VariantName::new(ts!(Left))), None);
441assert_eq!( right.field_(fp!(::Left)), None);
442
443
444////////////////////////////////////////////////////////////////////
445////            Constructing VariantField
446
447assert_eq!( left.field_(VariantField::new(ts!(Left),ts!(0))), Some(&3) );
448assert_eq!( left.field_(fp!(::Left.0)), Some(&3) );
449assert_eq!( left.field_(VariantField::new(ts!(Right),ts!(c))), None );
450assert_eq!( left.field_(fp!(::Right.c)), None );
451
452assert_eq!( right.field_(VariantField::new(ts!(Right),ts!(c))), Some(&'a') );
453assert_eq!( right.field_(fp!(::Right.c)), Some(&'a') );
454assert_eq!( right.field_(VariantField::new(ts!(Left),ts!(0))), None );
455assert_eq!( right.field_(fp!(::Left.0)), None );
456
457
458////////////////////////////////////////////////////////////////////
459////               Constructing `FieldPathSet`
460////
461//// Note that you can't safely construct a FieldPathSet to
462//// access multiple fields mutably (which might access overlapping fields),
463//// it requires calling the unsafe `upgrade_unchecked` method after
464//// constructing the FieldPathSet.
465
466// These don't have an equivalent syntax in the `fp` macro.
467assert_eq!( tuple.fields(FieldPathSet::one(path_0)), (&3,) );
468assert_eq!( tuple.fields(FieldPathSet::one(path_1)), (&5,) );
469assert_eq!( tuple.fields(FieldPathSet::one(path_2_0)), (&8,) );
470assert_eq!( tuple.fields(FieldPathSet::one(path_2_1)), (&80,) );
471assert_eq!( tuple.fields(FieldPathSet::one(path_2_2)), (&800,) );
472
473assert_eq!( tuple.fields(FieldPathSet::many((path_0, path_1))), (&3,&5) );
474assert_eq!( tuple.fields(fp!(0, 1)), (&3,&5) );
475
476assert_eq!( tuple.fields(FieldPathSet::many((path_1, path_2_0))), (&5,&8) );
477assert_eq!( tuple.fields(fp!(1, 2.0)), (&5,&8) );
478
479assert_eq!(
480    tuple.fields(FieldPathSet::many((path_2_0, path_2_1, path_2_2))),
481    (&8, &80, &800),
482);
483assert_eq!( tuple.fields(fp!(2.0, 2.1, 2.2)), (&8, &80, &800));
484
485
486////////////////////////////////////////////////////////////////////
487////               Constructing `NestedFieldPathSet`
488////
489//// Note that you can't safely construct a NestedFieldPathSet to
490//// access multiple fields mutably(which might access overlapping fields),
491//// it requires calling the unsafe `upgrade_unchecked` method after
492//// constructing the `NestedFieldPathSet`.
493
494let left=Binary::Left(3,5);
495let right=Binary::Right{c: 'a', is_true: false};
496
497let nested_a=NestedFieldPathSet::new(
498    VariantName::new(ts!(Left)),
499    FieldPathSet::many(( ts!(0), ts!(1) )),
500);
501let nested_b=NestedFieldPathSet::new(
502    VariantName::new(ts!(Right)),
503    FieldPathSet::many(( ts!(c), ts!(is_true) )),
504);
505
506assert_eq!( left.cloned_fields(nested_a), Some((3,5)) );
507assert_eq!( left.cloned_fields(fp!(::Left=>0,1)), Some((3,5)) );
508
509assert_eq!( left.cloned_fields(nested_b), None );
510assert_eq!( left.cloned_fields(fp!(::Right=>c,is_true)), None );
511
512
513assert_eq!( right.cloned_fields(nested_a), None );
514assert_eq!( right.cloned_fields(fp!(::Left=>0,1)), None );
515
516assert_eq!( right.cloned_fields(nested_b), Some(('a',false)) );
517assert_eq!( right.cloned_fields(fp!(::Right=>c,is_true)), Some(('a',false)) );
518
519
520
521
522
523
524```
525
526
527*/
528#[macro_export]
529macro_rules! ts {
530    ($anything:tt) => {
531        <$crate::TS!($anything)>::NEW
532    };
533}