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}