dioxus_shareables/
struct.rs

1pub trait ShareableStruct: Sized {
2    type Fields;
3    type Actions;
4}
5pub trait FieldOf<S: ShareableStruct> {
6    type RWType;
7    type WType;
8    const RW: Self::RWType;
9    const W: Self::WType;
10}
11pub trait InitWith<O: super::InitType>: super::InitType {
12    type Flag: super::InitType;
13}
14impl InitWith<()> for () {
15    type Flag = ();
16}
17impl InitWith<super::W> for () {
18    type Flag = super::W;
19}
20impl InitWith<super::RW> for () {
21    type Flag = super::RW;
22}
23impl InitWith<()> for super::W {
24    type Flag = super::W;
25}
26impl InitWith<super::W> for super::W {
27    type Flag = super::W;
28}
29impl InitWith<super::RW> for super::W {
30    type Flag = super::RW;
31}
32impl InitWith<()> for super::RW {
33    type Flag = super::RW;
34}
35impl InitWith<super::W> for super::RW {
36    type Flag = super::RW;
37}
38impl InitWith<super::RW> for super::RW {
39    type Flag = super::RW;
40}
41pub trait ImpliesInitField<O: super::InitType>: super::InitType {}
42impl<A: super::InitType, B: InitWith<A, Flag = A>> ImpliesInitField<B> for A {}
43
44pub trait InitField<F> {
45    type Flag: super::InitType;
46}
47impl<F> InitField<F> for () {
48    type Flag = ();
49}
50impl<F, T: super::InductiveMarkerTuple> InitField<F> for T
51where
52    T::Step: InitField<F>,
53    T::Base: InitField<F>,
54    <T::Base as InitField<F>>::Flag: InitWith<<T::Step as InitField<F>>::Flag>,
55{
56    type Flag =
57        <<T::Base as InitField<F>>::Flag as InitWith<<T::Step as InitField<F>>::Flag>>::Flag;
58}
59pub trait InitSubstruct<F> {
60    type Actions;
61    fn substruct_actions(&self) -> Self::Actions;
62}
63impl<F> InitSubstruct<F> for () {
64    type Actions = ();
65    fn substruct_actions(&self) {}
66}
67impl<F, T: super::InductiveMarkerTuple> InitSubstruct<F> for T
68where
69    T::Step: InitSubstruct<F> + Copy,
70    T::Base: InitSubstruct<F> + Copy,
71{
72    type Actions = (
73        <T::Base as InitSubstruct<F>>::Actions,
74        <T::Step as InitSubstruct<F>>::Actions,
75    );
76    fn substruct_actions(&self) -> Self::Actions {
77        (
78            self.base().substruct_actions(),
79            self.step().substruct_actions(),
80        )
81    }
82}
83
84pub trait WriteActions {}
85impl WriteActions for () {}
86impl<T: super::InductiveMarkerTuple> WriteActions for T
87where
88    T::Base: WriteActions,
89    T::Step: WriteActions,
90{
91}
92
93pub trait InitFieldAs<F, Flag: super::InitType>: InitField<F> {}
94impl<F, T: InitField<F>, Flag: super::InitType> InitFieldAs<F, Flag> for T where
95    <T as InitField<F>>::Flag: ImpliesInitField<Flag>
96{
97}
98
99/// &'static str is not allowed for const generics, but we can imitate a &'static [u8; 256] bound
100/// using a lot of ints here.
101pub trait AssocType<
102    const _0: u128,
103    const _1: u128,
104    const _2: u128,
105    const _3: u128,
106    const _4: u128,
107    const _5: u128,
108    const _6: u128,
109    const _7: u128,
110    const _8: u128,
111    const _9: u128,
112    const _10: u128,
113    const _11: u128,
114    const _12: u128,
115    const _13: u128,
116    const _14: u128,
117    const _15: u128,
118>
119{
120    type Type;
121}
122pub const fn seg_str(s: &'static str, r: usize) -> u128 {
123    let mut i = 0usize;
124    let mut c = 0;
125    loop {
126        if i >= 16 || r + i >= s.len() {
127            return c;
128        }
129        c += (s.as_bytes()[r + i] as u128) << (8 * i);
130        i += 1;
131    }
132}
133
134/// Create a `struct` definition for a global.
135///
136/// The idea is that each field of the struct will be stored in a separate global, and loaded only
137/// when requested. The actions block describes possible ways of using the struct in terms of what
138/// type of access ([`W`](crate::W) or [`RW`](crate::RW)) they need to fields of the struct.
139///
140/// The basic syntax is as follows:
141/// ```
142///     dioxus_shareables::shareable_struct! {
143///         pub struct GlobalState {
144///             a: usize = 8,
145///             b: u16 = 12,
146///             c: Vec<u8> = vec![],
147///         }
148///
149///         action A impl pub ATrait = W[a] RW[b]; // Action A with equivalent trait ATrait
150///         pub action B: BType = W[b] RW[a, c]; // Action B with equivalent type BType
151///         action C: pub CType = RW[c]; // Action C with equivalent type CType
152///         action D_ACTION impl pub D = W[c]; // Action D_ACTION with equivalent trait D.
153///     }
154/// ```
155/// NOTE: fields in the struct must be `Send + Sync`
156///
157/// First we declare the struct itself, then "actions" which represent different views of the
158/// struct. When we use the struct, we then have to declare which actions we need:
159///
160/// ```
161///     # use dioxus::prelude::*;
162///     # dioxus_shareables::shareable_struct! {
163///     #     pub struct GlobalState {
164///     #         a: usize = 8,
165///     #         b: u16 = 12,
166///     #         c: Vec<u8> = vec![],
167///     #     }
168///     #
169///     #   action A impl pub ATrait = W[a] RW[b]; // Action A with equivalent trait ATrait
170///     #   pub action B: BType = W[b] RW[a, c]; // Action B with equivalent type BType
171///     #   action C: pub CType = RW[c]; // Action C with equivalent type CType
172///     #   action D_ACTION impl pub D = W[c]; // Action D_ACTION with equivalent trait D.
173///     # }
174///     # #[allow(non_snake_case)]
175///     fn Component(cx: Scope) -> Element {
176///         let state = GlobalState::use_(&cx, (A, B)); // Use GlobalState with actions A and B.
177///         // ...
178///         let b = *state.b().read(); // We can access field b because actions B includes it.
179///         //...
180///         # cx.render(rsx! {
181///         #     div {
182///         #       onmousedown: |_| { *state.a().write() += 1; },
183///         #       onmouseover: |_| { *state.b().write() -= 3; }
184///         #     }
185///         # })
186///     }
187/// ```
188///
189/// Of course, there's not a lot of point to grouping shared variables into a type if we don't
190/// implement some methods on the type. This is where the types on the actions come in:
191/// ```
192///     # use dioxus::prelude::*;
193///     # dioxus_shareables::shareable_struct! {
194///     #     pub struct GlobalState {
195///     #         a: usize = 8,
196///     #         b: u16 = 12,
197///     #         c: Vec<u8> = vec![],
198///     #     }
199///     #
200///     #   action A = W[a] RW[b]; // Action A with equivalent trait ATrait
201///     #   pub action B: BType = W[b] RW[a, c]; // Action B with equivalent type BType
202///     #   action C: pub CType = RW[c]; // Action C with equivalent type CType
203///     #   action D_ACTION impl pub D = W[c]; // Action D_ACTION with equivalent trait D.
204///     # }
205///     impl GlobalState<CType> {
206///         pub fn c_method(&self) {
207///             // Do some stuff...
208///         }
209///     }
210///     // Valid action markers implement GlobalStateActions:
211///     impl<Actions: GlobalStateActions> GlobalState<Actions> {
212///         // N.B. that D is the trait, not the actions constant:
213///         pub fn clever_d_method(&self) where Actions: D {
214///             let self_ = self.with_actions(D_ACTION); // We probably want to typecast
215///                                                      // at the start of the method.
216///             // ...
217///         }
218///     }
219///     // ...
220///     # #[allow(non_snake_case)]
221///     fn Component(cx: Scope) -> Element {
222///         let a_state = GlobalState::use_(&cx, A);
223///         let b_state = GlobalState::use_(&cx, B);
224///         let c_state = GlobalState::use_(&cx, C);
225///
226///         // a_state.c_method(); // This will fail since `a_state` doesn't doesn't meet the RW[c] requirement.
227///         // b_state.c_method(); // This will fail because the type is wrong.
228///         b_state.as_ref().c_method(); // This works, but only if the type resolves correctly.
229///         b_state.with_actions(C).c_method(); // This is guaranteed to work.
230///         c_state.c_method(); // This works too.
231///
232///         // a_state.clever_d_method(); // Fails because a_state doesn't meet the W[c] requirement.
233///         b_state.clever_d_method(); // This works.
234///         c_state.clever_d_method(); // So does this.
235///         # cx.render(rsx! { div {} })
236///     }
237/// ```
238///
239/// It's up to you where you prefer to typecast.
240///
241/// You don't need to declare actions in advance to use them; in particular, you may want to use
242/// one-off action declarations on method declarations:
243/// ```
244///     # use dioxus::prelude::*;
245///     # dioxus_shareables::shareable_struct! {
246///     #     pub struct GlobalState {
247///     #         a: usize = 8,
248///     #         b: u16 = 12,
249///     #         c: Vec<u8> = vec![],
250///     #     }
251///     #
252///     #   action A = W[a] RW[b]; // Action A with equivalent trait ATrait
253///     #   pub action B: BType = W[b] RW[a, c]; // Action B with equivalent type BType
254///     #   action C: pub CType = RW[c]; // Action C with equivalent type CType
255///     #   action D_ACTION impl pub D = W[c]; // Action D_ACTION with equivalent trait D.
256///     # }
257///     impl<Actions: GlobalStateActions> GlobalState<Actions> {
258///         pub fn calculate_from_a_and_c(&self) -> usize where Actions:
259///             AsGlobalStateActions<dioxus_shareables::struct_actions!{GlobalState<{RW[a] RW[c]}>}>
260///         {
261///             let self_ = self.with_actions(dioxus_shareables::struct_actions!(GlobalState(RW[a] RW[c])));
262///             self_.a(); // you asked for it, you got it.
263///             // ...
264///             # 3
265///         }
266///     }
267///     // ...
268///     # #[allow(non_snake_case)]
269///     fn Component(cx: Scope) -> Element {
270///         let a_state = GlobalState::use_(&cx, A);
271///         let b_state = GlobalState::use_(&cx, B);
272///
273///         // a_state.calculate_from_a_and_c(); // This will fail since `a_state` doesn't meet the RW[c] requirement.
274///         b_state.calculate_from_a_and_c(); // This works, but only if the type resolves correctly.
275///         # cx.render(rsx! { div {} })
276///     }
277/// ```
278///
279///
280/// If you'd like, you can also organize your shared structure into substructures. A substructure
281/// can be included in a larger shared structure by preceding the field name with a pipe like so:
282/// ```
283///     # use dioxus::prelude::*;
284///     # dioxus_shareables::shareable_struct! {
285///     #     pub struct GlobalState {
286///     #         a: usize = 8,
287///     #         b: u16 = 12,
288///     #         c: Vec<u8> = vec![],
289///     #     }
290///     #
291///     #   action A = W[a] RW[b]; // Action A with equivalent trait ATrait
292///     #   pub action B: BType = W[b] RW[a, c]; // Action B with equivalent type BType
293///     #   action C: pub CType = RW[c]; // Action C with equivalent type CType
294///     #   action D_ACTION impl pub D = W[c]; // Action D_ACTION with equivalent trait D.
295///     # }
296///     # impl<Actions: GlobalStateActions> GlobalState<Actions> {
297///     #     // N.B. that D is the trait, not the actions constant:
298///     #     pub fn clever_d_method(&self) where Actions: D {
299///     #         let self_ = self.with_actions(D_ACTION); // We probably want to typecast
300///     #                                                  // at the start of the method.
301///     #         // ...
302///     #     }
303///     # }
304///     dioxus_shareables::shareable_struct! {
305///         pub struct MoreGlobalState {
306///             u: String = "more global? more state? which is it?!".into(),
307///             v: u32 = 18,
308///             |s: GlobalState,
309///         }
310///         action UVA = W[u] RW[v] |s[A]; // The included actions for s here must be a single
311///                                        // ident which refers to a declared action for the
312///                                        // given struct.
313///         action UBC = W[u] |s[B]; // N.B.: The syntax doesn't change if B isn't in scope... B is
314///                                  // accessed as an associated type of GlobalState.
315///                                  // If you get errors involving `AssocType` bounds, this is a
316///                                  // these |s[B] style bounds are the most likely candidtates.
317///     }
318///     // ...
319///     # #[allow(non_snake_case)]
320///     fn Component(cx: Scope) -> Element {
321///         let mgs = MoreGlobalState::use_(&cx, UBC);
322///         mgs.s().clever_d_method(); // Works bcause action our mgs.s() was initialized with the
323///                                    // `B` action.
324///         // ...
325///         # cx.render(rsx! { div {} })
326///     }
327/// ```
328#[macro_export]
329macro_rules! shareable_struct {
330    (
331        $(#[$meta:meta])*
332        $v:vis struct $Struct:ident {
333            $($fields:tt)*
334        }
335        $($actions:tt)*
336    ) => {
337        $crate::shareable_struct_parse_actions! {
338            remaining_actions: {$($actions)*}
339            vis: [$v]
340            struct: [$Struct]
341            meta: [$(#[$meta])*]
342            fields: {$($fields)*}
343            parsed_actions: []
344        }
345    };
346}
347
348#[doc(hidden)]
349#[macro_export]
350macro_rules! shareable_struct_parse_actions {
351    ( remaining_actions: {$av:vis action $ACTION:ident$(: $ATv:vis $ATy:ident)?$(impl $ATrv:vis $ATr:ident)? = $($r:tt)*}
352      vis: $v:tt
353      struct: $s:tt
354      meta: $m:tt
355      fields: $f:tt
356      parsed_actions: $a:tt
357    ) => {
358        $crate::shareable_struct_parse_action_flags! {
359            remaining_actions: {$($r)*}
360            vis: $v
361            struct: $s
362            meta: $m
363            fields: $f
364            parsed_actions: $a
365            action: [[$ACTION] vis: [$av] type: [$($ATv$ATy)?] trait: [$($ATrv$ATr)?]]
366            w: []
367            rw: []
368            sub: []
369        }
370    };
371    ( remaining_actions: {}
372      vis: $v:tt
373      struct: $s:tt
374      meta: $m:tt
375      fields: $f:tt
376      parsed_actions: $a:tt
377    ) => {
378        $crate::shareable_struct_parse_fields! {
379            remaining_fields: $f
380            vis: $v
381            struct: $s
382            meta: $m
383            standard_fields: []
384            substruct_fields: []
385            actions: $a
386        }
387    };
388}
389
390#[doc(hidden)]
391#[macro_export]
392macro_rules! shareable_struct_parse_action_flags {
393    ( remaining_actions: {W[$($w2:ident),*]$($r:tt)*}
394      vis: $v:tt
395      struct: $s:tt
396      meta: $m:tt
397      fields: $f:tt
398      parsed_actions: $a:tt
399      action: $ad:tt
400      w: [$($w:tt)*]
401      rw: $rw:tt
402      sub: $sub:tt
403    ) => {
404        $crate::shareable_struct_parse_action_flags! {
405            remaining_actions: {$($r)*}
406            vis: $v
407            struct: $s
408            meta: $m
409            fields: $f
410            parsed_actions: $a
411            action: $ad
412            w: [$($w)*$(,$w2)*]
413            rw: $rw
414            sub: $sub
415        }
416    };
417    ( remaining_actions: {RW[$($rw2:ident),*]$($r:tt)*}
418      vis: $v:tt
419      struct: $s:tt
420      meta: $m:tt
421      fields: $f:tt
422      parsed_actions: $a:tt
423      action: $ad:tt
424      w: $w:tt
425      rw: [$($rw:tt)*]
426      sub: $sub:tt
427    ) => {
428        $crate::shareable_struct_parse_action_flags! {
429            remaining_actions: {$($r)*}
430            vis: $v
431            struct: $s
432            meta: $m
433            fields: $f
434            parsed_actions: $a
435            action: $ad
436            w: $w
437            rw: [$($rw)*$(,$rw2)*]
438            sub: $sub
439        }
440    };
441    ( remaining_actions: {|$g:ident[$ga:ident]$($r:tt)*}
442      vis: $v:tt
443      struct: $s:tt
444      meta: $m:tt
445      fields: $f:tt
446      parsed_actions: $a:tt
447      action: $ad:tt
448      w: $w:tt
449      rw: $rw:tt
450      sub: [$($sub:tt)*]
451    ) => {
452        $crate::shareable_struct_parse_action_flags! {
453            remaining_actions: {$($r)*}
454            vis: $v
455            struct: $s
456            meta: $m
457            fields: $f
458            parsed_actions: $a
459            action: $ad
460            w: $w
461            rw: $rw
462            sub: [$($sub)*sub_actions { sub: [$g] actions: [$ga] }]
463        }
464    };
465    ( remaining_actions: {;$($r:tt)*}
466      vis: $v:tt
467      struct: $s:tt
468      meta: $m:tt
469      fields: $f:tt
470      parsed_actions: [$($a:tt)*]
471      action: [[$action:ident]$($ad:tt)*]
472      w: $w:tt
473      rw: $rw:tt
474      sub: $sub:tt
475    ) => {
476        $crate::shareable_struct_parse_actions! {
477            remaining_actions: {$($r)*}
478            vis: $v
479            struct: $s
480            meta: $m
481            fields: $f
482            parsed_actions: [$($a)*
483                action $action {
484                    $($ad)*
485                    w: $w
486                    rw: $rw
487                    sub: $sub
488                }
489            ]
490        }
491    };
492}
493
494#[doc(hidden)]
495#[macro_export]
496macro_rules! shareable_struct_parse_fields {
497    ( remaining_fields: {$fvis:vis $f:ident: $T:ty = $init:expr$(,$($r:tt)*)?}
498      vis: $v:tt
499      struct: $s:tt
500      meta: $m:tt
501      standard_fields: [$($ff:tt)*]
502      substruct_fields: $g:tt
503      actions: $a:tt
504    ) => {
505        $crate::shareable_struct_parse_fields! {
506            remaining_fields: {$($($r)*)?}
507            vis: $v
508            struct: $s
509            meta: $m
510            standard_fields: [$($ff)*field $f { vis: [$fvis] type: [$T] init: [$init] }]
511            substruct_fields: $g
512            actions: $a
513        }
514    };
515    ( remaining_fields: {}
516      vis: $v:tt
517      struct: $s:tt
518      meta: $m:tt
519      standard_fields: $f:tt
520      substruct_fields: $g:tt
521      actions: $a:tt
522    ) => {
523        $crate::shareable_struct_main! {
524            vis: $v
525            struct: $s
526            meta: $m
527            standard_fields: $f
528            substruct_fields: $g
529            actions: $a
530        }
531    };
532    ( remaining_fields: {|$gvis:vis $g:ident: $T:ident$(::$Tc:ident)*$(,$($r:tt)*)?}
533      vis: $v:tt
534      struct: $s:tt
535      meta: $m:tt
536      standard_fields: $f:tt
537      substruct_fields: $gg:tt
538      actions: $a:tt
539    ) => {
540        $crate::shareable_struct_parse_substruct_path! {
541            rest: [$($Tc)*]
542            vis: $v
543            struct: $s
544            meta: $m
545            standard_fields: $f
546            substruct_fields: $gg
547            remaining_fields: {$($($r)*)?}
548            actions: $a
549            substruct_field: [field $g { vis: [$gvis] }]
550            head: [::]
551            tail: $T
552        }
553    };
554}
555
556#[doc(hidden)]
557#[macro_export]
558macro_rules! shareable_struct_parse_substruct_path {
559    ( rest: [$Tn:ident$($Tc:tt)*]
560      vis: $v:tt
561      struct: $s:tt
562      meta: $m:tt
563      standard_fields: $f:tt
564      substruct_fields: $gg:tt
565      remaining_fields: $r:tt
566      actions: $a:tt
567      substruct_field: $g:tt
568      head: [$($h:tt)*]
569      tail: $Tl:ident
570    ) => {
571        $crate::shareable_struct_parse_substruct_path! {
572            rest: [$($Tc)*]
573            vis: $v
574            struct: $s
575            meta: $m
576            standard_fields: $f
577            substruct_fields: $gg
578            remaining_fields: $r
579            actions: $a
580            substruct_field: $g
581            head: [$($h)*$Tl::]
582            tail: $Tn
583        }
584    };
585    ( rest: []
586      vis: $v:tt
587      struct: $s:tt
588      meta: $m:tt
589      standard_fields: $f:tt
590      substruct_fields: [$($gg:tt)*]
591      remaining_fields: $r:tt
592      actions: $a:tt
593      substruct_field: [field $g:ident { vis: [$gvis:vis] }]
594      head: [::$($h:tt)*]
595      tail: $Tl:ident
596    ) => {
597        $crate::reexported::paste! {
598            $crate::shareable_struct_parse_fields! {
599                remaining_fields: $r
600                vis: $v
601                struct: $s
602                meta: $m
603                standard_fields: $f
604                substruct_fields: [$($gg)*field $g { vis: [$gvis] struct: [$($h)*$Tl] actions: [$($h)*[<$Tl Actions>]] as_actions: [$($h)*[<As $Tl Actions>]] }]
605                actions: $a
606            }
607        }
608    };
609}
610
611#[doc(hidden)]
612#[macro_export]
613macro_rules! shareable_struct_main {
614    ( vis: [$v:vis]
615      struct: [$Struct:ident]
616      meta: [$(#[$meta:meta])*]
617      standard_fields: [
618          $(field $f:ident {
619              vis: [$fvis:vis]
620              type: [$fT:ty]
621              init: [$init:expr]
622          })*
623      ]
624      substruct_fields: [
625          $(field $g:ident {
626              vis: [$gvis:vis]
627              struct: [$gT:ty]
628              actions:
629              [$gAT:ty]
630              as_actions: [$AgAT:ty]
631          })*
632      ]
633      actions: [ $(
634          action $ACTION:ident {
635              vis: [$av:vis]
636              type: [$($ATv:vis$ATy:ident)?]
637              trait: [$($ATrv:vis$ATr:ident)?]
638              w: [$(,$w:ident)*]
639              rw: [$(,$rw:ident)*]
640              sub: [$(sub_actions { sub: [$sa:ident] actions: [$saA:ident] })*]
641          }
642      )* ]
643    ) => {
644        $crate::reexported::paste! {
645            $(#[$meta])*
646            $v struct $Struct<__Actions: [<$Struct Actions>] = ()> {
647                $($f: Option<$crate::Shared<$fT, <__Actions as [<$Struct Actions>]>::[<$f:camel Flag>]>>,)*
648                $($g: $gT<<__Actions as [<$Struct Actions>]>::[<$g:camel Actions>]>,)*
649                #[doc(hidden)]
650                __actions_marker: std::marker::PhantomData<__Actions>,
651            }
652            impl<__Actions: [<$Struct Actions>]> $Struct<__Actions> {
653                $v fn share(__a: __Actions) -> Self where __Actions: $crate::r#struct::WriteActions $(, <__Actions as [<$Struct Actions>]>::[<$g:camel Actions>]: $crate::r#struct::WriteActions)* {
654                    #[allow(unused_mut)]
655                    let mut self_ = Self {
656                        $($f: None,)*
657                        $($g: $gT::share([<$Struct Actions>]::[<$g _actions>](&__a)),)*
658                        __actions_marker: std::marker::PhantomData,
659                    };
660                    $(
661                        <__Actions::[<$f:camel Flag>] as $crate::InitType>::share_field(
662                            &mut self_.$f,
663                            <Self as $crate::r#struct::ShareableStruct>::Fields::[<$f:snake:upper>],
664                        );
665                    )*
666                    self_
667                }
668                #[doc(hidden)]
669                $v fn __uninit() -> Self {
670                    Self {
671                        $($f: None,)*
672                        $($g: $gT::__uninit(),)*
673                        __actions_marker: std::marker::PhantomData,
674                    }
675                }
676                #[doc(hidden)]
677                $v fn __init_in<P>(&mut self, cx: &$crate::reexported::Scope<P>) {
678                    $(
679                        <__Actions::[<$f:camel Flag>] as $crate::InitType>::init_field(
680                            cx,
681                            &mut self.$f,
682                            <Self as $crate::r#struct::ShareableStruct>::Fields::[<$f:snake:upper>],
683                        );
684                    )*
685                    $(
686                        self.$g.__init_in(cx);
687                    )*
688                }
689                $v fn use_<'a, P>(cx: &$crate::reexported::Scope<'a, P>, _: __Actions) -> &'a mut Self {
690                    cx.use_hook(|| {
691                        let mut self_ = Self::__uninit();
692                        self_.__init_in(cx);
693                        self_
694                    })
695                }
696                $v fn with_actions<B: [<$Struct Actions>]>(&self, _: B) -> &$Struct<B>
697                where __Actions: [<As $Struct Actions>]<B>
698                {
699                    // SAFETY:
700                    //   * the layout of $Struct<F> does not depend on F.
701                    //   * the [<As $Struct Actions>] trait guarantees that an initialized $Struct<__Actions>
702                    //     has initialized all the fields that should be initialized in $Struct<B>
703                    unsafe { std::mem::transmute(self) }
704                }
705                $($fvis fn $f(&self) -> &$crate::Shared<$fT, <__Actions as [<$Struct Actions>]>::[<$f:camel Flag>]> where <__Actions as [<$Struct Actions>]>::[<$f:camel Flag>]: $crate::Flag {
706                    if let Some($f) = self.$f.as_ref() { $f }
707                    else { unreachable!{} }
708                })*
709                $($gvis fn $g(&self) -> &$gT<<__Actions as [<$Struct Actions>]>::[<$g:camel Actions>]> {
710                    &self.$g
711                })*
712            }
713            #[doc = "Actions on a " $Struct]
714            #[doc = "See [`dioxus_shareables::shareable_struct`] for more info"]
715            /// An actions object describes a collection of field access types you might use
716            /// together.
717            $v trait [<$Struct Actions>]: 'static + Copy {
718                $(type [<$f:camel Flag>]: $crate::InitType;)*
719                $(
720                    type [<$g:camel Actions>]: $gAT;
721                    fn [<$g _actions>](&self) -> Self::[<$g:camel Actions>];
722                )*
723            }
724            #[doc = "Marker trait for allowed conversions between `" [<$Struct Actions>] "` markers."]
725            #[doc = "Implementing this yourself can lead to undefined behavior."]
726            $v trait [<As $Struct Actions>]<B: [<$Struct Actions>]>: [<$Struct Actions>] {}
727            impl<A: [<$Struct Actions>], B: [<$Struct Actions>]> [<As $Struct Actions>]<B> for A
728            where
729                A: 'static
730                    $(+ $crate::r#struct::InitFieldAs<$crate::struct_assoc_type!{$Struct::Fields::$f}, <B as [<$Struct Actions>]>::[<$f:camel Flag>]>)*,
731                $(<A as [<$Struct Actions>]>::[<$g:camel Actions>]: $AgAT<<B as [<$Struct Actions>]>::[<$g:camel Actions>]>,)*
732            {
733            }
734            $(
735                $av const $ACTION: $crate::struct_assoc_type!{$Struct::Actions::$ACTION} = <$Struct as $crate::r#struct::ShareableStruct>::Actions::$ACTION;
736                $($ATv type $ATy = $crate::struct_assoc_type!{$Struct::Actions::$ACTION};)?
737                $(
738                    $ATrv trait $ATr: [<As $Struct Actions>]<$crate::struct_assoc_type!{$Struct::Actions::$ACTION}> {}
739                    impl<T: [<As $Struct Actions>]<$crate::struct_assoc_type!{$Struct::Actions::$ACTION}>> $ATr for T {}
740                )?
741            )*
742            impl<A: [<$Struct Actions>], B: [<As $Struct Actions>]<A>> AsRef<$Struct<A>> for $Struct<B> {
743                fn as_ref(&self) -> &$Struct<A> {
744                    // SAFETY:
745                    //   * the layout of $Struct<F> does not depend on F.
746                    //   * the [<As $Struct Actions>] trait guarantees that an initialized $Struct<B>
747                    //     has initialized all the fields that should be initialized in $Struct<A>
748                    unsafe { std::mem::transmute(self) }
749                }
750            }
751            impl<A: [<$Struct Actions>], B: [<As $Struct Actions>]<A>> AsMut<$Struct<A>> for $Struct<B> {
752                fn as_mut(&mut self) -> &mut $Struct<A> {
753                    // SAFETY:
754                    //   * the layout of $Struct<F> does not depend on F.
755                    //   * the [<As $Struct Actions>] trait guarantees that an initialized $Struct<B>
756                    //     has initialized all the fields that should be initialized in $Struct<A>
757                    unsafe { std::mem::transmute(self) }
758                }
759            }
760            #[allow(dead_code)]
761            const _: () = {
762                $v struct [<$Struct FieldData>];
763                $v struct [<$Struct ActionData>];
764                #[derive(Clone, Copy)]
765                $v struct InitAs<F, A>(F, A);
766
767                impl<__Actions: [<$Struct Actions>]> $crate::r#struct::ShareableStruct for $Struct<__Actions> {
768                    type Fields = [<$Struct FieldData>];
769                    type Actions = [<$Struct ActionData>];
770                }
771
772                $($crate::shareable!{$v [<$Struct FieldShareable $f:camel>]: $fT = $init}
773                    impl $crate::r#struct::FieldOf<$Struct> for [<$Struct FieldShareable $f:camel>] {
774                        type WType = InitAs<[<$Struct FieldShareable $f:camel>], $crate::W>;
775                        type RWType = InitAs<[<$Struct FieldShareable $f:camel>], $crate::RW>;
776                        const W: Self::WType = InitAs([<$Struct FieldShareable $f:camel>], $crate::W);
777                        const RW: Self::RWType = InitAs([<$Struct FieldShareable $f:camel>], $crate::RW);
778                    }
779                    impl $crate::r#struct::WriteActions for InitAs<[<$Struct FieldShareable $f:camel>], $crate::W> {}
780                )*
781                $(
782                    #[derive(Clone, Copy)]
783                    $v struct [<$Struct Substruct $g:camel>];
784                )*
785
786                impl [<$Struct FieldData>] {
787                    $($fvis const [<$f:snake:upper>]: [<$Struct FieldShareable $f:camel>] = [<$Struct FieldShareable $f:camel>];)*
788                }
789                impl [<$Struct ActionData>] {
790                    $(const $ACTION:
791                        (
792                            $(InitAs<[<$Struct FieldShareable $w:camel>], $crate::W>,)*
793                            $(InitAs<[<$Struct FieldShareable $rw:camel>], $crate::RW>,)*
794                            $(InitAs<[<$Struct Substruct $sa:camel>], $crate::struct_assoc_type!{$Struct::Substructs::$sa::Actions::$saA}>,)*
795                        ) = (
796                            $(InitAs([<$Struct FieldShareable $w:camel>], $crate::W),)*
797                            $(InitAs([<$Struct FieldShareable $rw:camel>], $crate::RW),)*
798                            $(InitAs([<$Struct Substruct $sa:camel>], <$crate::struct_assoc_type!{$Struct::Fields::$sa} as $crate::r#struct::ShareableStruct>::Actions::$saA),)*
799                        );
800                    )*
801                }
802                $crate::shareable_struct_init_as_fields!{
803                    remaining_fields: [$($f)*]
804                    struct: [$Struct]
805                    init_as: [InitAs]
806                    prev_fields: []
807                    substruct_fields: [$(field $g { type: [$gAT] })*]
808                }
809                $crate::shareable_struct_init_as_substructs!{
810                    remaining_fields: [$(field $g { type: [$gAT] })*]
811                    struct: [$Struct]
812                    init_as: [InitAs]
813                    prev_fields: []
814                    standard_fields: [$($f)*]
815                }
816                impl<A:
817                    'static + Copy
818                    $(+ $crate::r#struct::InitField<[<$Struct FieldShareable $f:camel>]>)*
819                    $(+ $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]>)*
820                    > [<$Struct Actions>] for A
821                where $(<A as $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]>>::Actions: $gAT),* {
822                    $(type [<$f:camel Flag>] = <A as $crate::r#struct::InitField<[<$Struct FieldShareable $f:camel>]>>::Flag;)*
823                    $(
824                        type [<$g:camel Actions>] = <A as $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]>>::Actions;
825                        fn [<$g _actions>](&self) -> Self::[<$g:camel Actions>] {
826                            <A as $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]>>::substruct_actions(self)
827                        }
828                    )*
829                }
830
831                $($crate::struct_assoc_type!{impl $Struct::Fields::$f for [<$Struct FieldData>] = [<$Struct FieldShareable $f:camel>]})*
832                $($crate::struct_assoc_type!{impl $Struct::Fields::$g for [<$Struct FieldData>] = $gT})*
833                $($crate::struct_assoc_type!{impl $Struct::Actions::$ACTION for [<$Struct ActionData>] =
834                    (
835                        $(InitAs<[<$Struct FieldShareable $w:camel>], $crate::W>,)*
836                        $(InitAs<[<$Struct FieldShareable $rw:camel>], $crate::RW>,)*
837                        $(InitAs<[<$Struct Substruct $sa:camel>], $crate::struct_assoc_type!{$Struct::Substructs::$sa::Actions::$saA}>,)*
838                    )
839                })*
840            };
841        }
842    };
843}
844
845#[doc(hidden)]
846#[macro_export]
847macro_rules! shareable_struct_init_as_fields {
848    ( remaining_fields: [$f:ident$($r:ident)*]
849      struct: [$Struct:ident]
850      init_as:  [$IA:ident]
851      prev_fields: [$($p:ident)*]
852      substruct_fields: [$(field $g:ident {type: [$gAT:ty]})*]
853    ) => {
854        $crate::reexported::paste! {
855            impl<A: $crate::InitType> $crate::r#struct::InitField<[<$Struct FieldShareable $f:camel>]> for InitAs<[<$Struct FieldShareable $f:camel>], A> {
856                type Flag = A;
857            }
858            $(impl<A: $crate::InitType> $crate::r#struct::InitField<[<$Struct FieldShareable $f:camel>]> for InitAs<[<$Struct FieldShareable $r:camel>], A> {
859                type Flag = ();
860            })*
861            $(impl<A: $crate::InitType> $crate::r#struct::InitField<[<$Struct FieldShareable $f:camel>]> for InitAs<[<$Struct FieldShareable $p:camel>], A> {
862                type Flag = ();
863            })*
864            $(impl<A: $gAT> $crate::r#struct::InitField<[<$Struct FieldShareable $f:camel>]> for InitAs<[<$Struct Substruct $g:camel>], A> {
865                type Flag = ();
866            })*
867        }
868        $crate::shareable_struct_init_as_fields!{
869            remaining_fields: [$($r)*]
870            struct: [$Struct]
871            init_as: [$IA]
872            prev_fields: [$($p)*$f]
873            substruct_fields: [$(field $g {type: [$gAT]})*]
874        }
875    };
876    ( remaining_fields: []
877      struct: $s:tt
878      init_as: $IA:tt
879      prev_fields: $p:tt
880      substruct_fields: $g:tt
881    ) => {};
882}
883
884#[doc(hidden)]
885#[macro_export]
886macro_rules! shareable_struct_init_as_substructs {
887    ( remaining_fields: [field $g:ident {type: [$gAT:ty]}$(field $r:ident {type: [$rAT:ty]})*]
888      struct: [$Struct:ident]
889      init_as:  [$IA:ident]
890      prev_fields: [$(field $p:ident {type: [$pAT:ty]})*]
891      standard_fields: [$($f:ident)*]
892    ) => {
893        $crate::reexported::paste! {
894            impl<A: $gAT> $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]> for InitAs<[<$Struct Substruct $g:camel>], A> {
895                type Actions = A;
896                fn substruct_actions(&self) -> A {self.1}
897            }
898            $(impl<A: $rAT> $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]> for InitAs<[<$Struct Substruct $r:camel>], A> {
899                type Actions = ();
900                fn substruct_actions(&self) -> () {}
901            })*
902            $(impl<A: $pAT> $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]> for InitAs<[<$Struct Substruct $p:camel>], A> {
903                type Actions = ();
904                fn substruct_actions(&self) -> () {}
905            })*
906            $(impl<A: $crate::InitType> $crate::r#struct::InitSubstruct<[<$Struct Substruct $g:camel>]> for InitAs<[<$Struct FieldShareable $f:camel>], A> {
907                type Actions = ();
908                fn substruct_actions(&self) -> () {}
909            })*
910        }
911        $crate::shareable_struct_init_as_substructs!{
912            remaining_fields: [$(field $r {type: [$rAT]})*]
913            struct: [$Struct]
914            init_as:  [$IA]
915            prev_fields: [$(field $p {type: [$pAT:ty]})*field $g {type: [$gAT]}]
916            standard_fields: [$($f)*]
917        }
918    };
919    ( remaining_fields: []
920      struct: $s:tt
921      init_as: $IA:tt
922      prev_fields: $p:tt
923      standard_fields: $g:tt
924    ) => {};
925}
926
927#[doc(hidden)]
928#[macro_export]
929macro_rules! struct_assoc_type {
930    ($Struct:ident::Actions::$action:ident) => {
931        $crate::reexported::paste! {
932            $crate::struct_assoc_type! {
933                @(<<$Struct as $crate::r#struct::ShareableStruct>::Actions as )([<Action $action:camel>])(>::Type)
934            }
935        }
936    };
937    ($Struct:ident::Fields::$field:ident) => {
938        $crate::reexported::paste! {
939            $crate::struct_assoc_type! {
940                @(<<$Struct as $crate::r#struct::ShareableStruct>::Fields as )([<Field $field:camel>])(>::Type)
941            }
942        }
943    };
944    ($Struct:ident::Substructs::$field:ident::Actions::$action:ident) => {
945        $crate::reexported::paste! {
946            $crate::struct_assoc_type! {
947                @(<<<<$Struct as $crate::r#struct::ShareableStruct>::Fields as )([<Field $field:camel>])(>::Type)
948                @(as $crate::r#struct::ShareableStruct>::Actions as)([<Action $action>])(>::Type)
949            }
950        }
951    };
952    (impl $Struct:ident::Actions::$action:ident for $T:ty = $($what:tt)*) => {
953        $crate::reexported::paste! {
954            $crate::struct_assoc_type! {
955                @(impl)([<Action $action:camel>])(for $T { type Type = $($what)*; })
956            }
957        }
958    };
959    (impl $Struct:ident::Fields::$field:ident for $T:ty = $($what:tt)*) => {
960        $crate::reexported::paste! {
961            $crate::struct_assoc_type! {
962                @(impl)([<Field $field:camel>])( for $T { type Type = $($what)*; })
963            }
964        }
965    };
966    ($(@($($before:tt)*)($($x:tt)*)($($after:tt)*))*) => {
967        $($($before)*$crate::r#struct::AssocType<
968            {$crate::r#struct::seg_str(stringify!{$($x)*}, 0)},
969            {$crate::r#struct::seg_str(stringify!{$($x)*}, 1)},
970            {$crate::r#struct::seg_str(stringify!{$($x)*}, 2)},
971            {$crate::r#struct::seg_str(stringify!{$($x)*}, 3)},
972            {$crate::r#struct::seg_str(stringify!{$($x)*}, 4)},
973            {$crate::r#struct::seg_str(stringify!{$($x)*}, 5)},
974            {$crate::r#struct::seg_str(stringify!{$($x)*}, 6)},
975            {$crate::r#struct::seg_str(stringify!{$($x)*}, 7)},
976            {$crate::r#struct::seg_str(stringify!{$($x)*}, 8)},
977            {$crate::r#struct::seg_str(stringify!{$($x)*}, 9)},
978            {$crate::r#struct::seg_str(stringify!{$($x)*}, 10)},
979            {$crate::r#struct::seg_str(stringify!{$($x)*}, 11)},
980            {$crate::r#struct::seg_str(stringify!{$($x)*}, 12)},
981            {$crate::r#struct::seg_str(stringify!{$($x)*}, 13)},
982            {$crate::r#struct::seg_str(stringify!{$($x)*}, 14)},
983            {$crate::r#struct::seg_str(stringify!{$($x)*}, 15)},
984        >$($after)*)*
985    }
986}
987
988/// Get actions on a struct.
989///
990/// For example `dioxus_shareables::struct_actions!(GlobalState<{W[a] RW[b]}>)` gives the correct
991/// type for a `dioxus_shareables` struct with write access to field `a` and read-write access to
992/// field `b`, and `dioxus_shareables::struct_actions!(GlobalState(W[a] RW[b]))` gives a
993/// corresponding expression.
994#[macro_export]
995macro_rules! struct_actions {
996    ($Struct:ident$(::$Struct_:ident)*<{$($ty:tt)*}>) => {
997        $crate::struct_actions_! {
998            unparsed: [$($ty)*]
999            produce: ty
1000            struct: [$Struct$(::$Struct_)*]
1001        }
1002    };
1003    ($Struct:ident$(::$Struct_:ident)*($($ty:tt)*)) => {
1004        $crate::struct_actions_! {
1005            unparsed: [$($ty)*]
1006            produce: expr
1007            struct: [$Struct$(::$Struct_)*]
1008        }
1009    };
1010}
1011#[doc(hidden)]
1012#[macro_export]
1013macro_rules! struct_actions_ {
1014    (
1015        unparsed: []
1016        produce: $t:tt
1017        struct: [$Struct:path]
1018    ) => {
1019        ()
1020    };
1021    (
1022        unparsed: [W[$($w:ident)*]$($r:tt)*]
1023        produce: ty
1024        struct: [$($Struct:tt)*]
1025    ) => {
1026        (
1027            ($(
1028                <$crate::struct_assoc_type!($Struct::Fields::$w) as $crate::r#struct::FieldOf<$Struct>>::WType
1029            ),*),
1030            $crate::struct_actions_! {
1031                unparsed: [$($r)*]
1032                produce: ty
1033                struct: [$($Struct)*]
1034            }
1035        )
1036    };
1037    (
1038        unparsed: [RW[$($w:ident)*]$($r:tt)*]
1039        produce: ty
1040        struct: [$($Struct:tt)*]
1041    ) => {
1042        (
1043            ($(
1044                <$crate::struct_assoc_type!($Struct::Fields::$w) as $crate::r#struct::FieldOf<$Struct>>::RWType
1045            ),*),
1046            $crate::struct_actions_! {
1047                unparsed: [$($r)*]
1048                produce: ty
1049                struct: [$($Struct)*]
1050            }
1051        )
1052    };
1053    (
1054        unparsed: [W[$($w:ident)*]$($r:tt)*]
1055        produce: expr
1056        struct: [$($Struct:tt)*]
1057    ) => {
1058        (
1059            ($(
1060                <$crate::struct_assoc_type!($Struct::Fields::$w) as $crate::r#struct::FieldOf<$Struct>>::W
1061            ),*),
1062            $crate::struct_actions_! {
1063                unparsed: [$($r)*]
1064                produce: expr
1065                struct: [$($Struct)*]
1066            }
1067        )
1068    };
1069    (
1070        unparsed: [RW[$($w:ident)*]$($r:tt)*]
1071        produce: expr
1072        struct: [$($Struct:tt)*]
1073    ) => {
1074        (
1075            ($(
1076                <$crate::struct_assoc_type!($Struct::Fields::$w) as $crate::r#struct::FieldOf<$Struct>>::RW
1077            ),*),
1078            $crate::struct_actions_! {
1079                unparsed: [$($r)*]
1080                produce: expr
1081                struct: [$($Struct)*]
1082            }
1083        )
1084    };
1085}