wiwi_wasm/
util.rs

1//! Common builder API utilities and stuffs
2
3// Checklist™
4// - use statements
5// - builder struct (with repr(transparent), `inner`, `__marker`)
6// - builder inner struct
7// - state trait
8// - state container struct
9// - type definitions for important states
10// - impl state for statecontainer
11// - impl builder uninit
12// - impl blocks for finished ones with `call` or `build` fns
13// - impl block for builder fns, `change_state`, internal functions etc
14
15// Checklist™ v2
16// - use statements
17// - builder struct (with repr(transparent), `inner`, `__marker`)
18// - builder inner struct
19// - `gen_state!` invocation (generates state trait, state
20//   container struct, uninit type def, impl state for statecontainer)
21// - impl builder uninit
22// - impl blocks for finished ones with `call_fn` or `build` fns
23// - impl block for builder fns, `change_state`, internal functions etc
24// - target slot union definitions (will want `uninit`, likely will
25//   want `any`, and whatever other incompatible types in there), and
26//   associated impls (`Slot` impls etc)
27
28pub use self::marker::*;
29pub use core::marker::PhantomData;
30
31pub mod marker;
32
33/// Marker struct for a field in the uninitialised state
34pub struct Uninit {
35	__private: ()
36}
37
38/// Marker struct for a field in the initialised state, optionally
39/// containing more state in the form of another type `S`, and a more
40/// "general" type that can be "matched upon" in implementations, in `T`
41pub struct Init<T = (), M = ()>
42where
43	T: ?Sized,
44	M: ?Sized + TypeMarker
45{
46	// need two seperate markers because `T` and `M` are `?Sized`
47	__marker_t: PhantomDataInvariant<T>,
48	__marker_g: PhantomDataInvariant<M>
49}
50
51/// Trait for marker structs to hold state about if a field in
52/// a builder is initialised or not
53///
54/// # Safety
55///
56/// [`IS_INIT`] and [`IS_UNINIT`] must both be set correctly to acccurately
57/// represent the state of the field. If you set [`IS_INIT`] correctly, there is
58/// a default implementation for [`IS_UNINIT`] which is just an inversion of
59/// [`IS_INIT`], and therefore always correct.
60///
61/// [`IS_INIT`]: InitStatus::IS_INIT
62/// [`IS_UNINIT`]: InitStatus::IS_UNINIT
63pub unsafe trait InitStatus {
64	const IS_INIT: bool;
65	const IS_UNINIT: bool = !Self::IS_INIT;
66}
67
68// SAFETY: `Uninit` represents uninitialised
69unsafe impl InitStatus for Uninit {
70	const IS_INIT: bool = false;
71}
72
73// SAFETY: `Init` represents initialised
74unsafe impl<T, M> InitStatus for Init<T, M>
75where
76	T: ?Sized,
77	M: ?Sized + TypeMarker
78{
79	const IS_INIT: bool = true;
80}
81
82/// Marker trait for marker structs that represent uninitialised state
83///
84/// # Safety
85///
86/// Marker struct must actually represent an uninitialised state.
87#[diagnostic::on_unimplemented(
88	message = "this field has already been initialised"
89)]
90pub unsafe trait IsUninit: InitStatus {}
91
92// SAFETY: `Uninit` represents uninitialised
93unsafe impl IsUninit for Uninit {}
94
95/// Marker trait for marker structs that represent initialised state
96///
97/// # Safety
98///
99/// Marker struct must actually represent an initialised state.
100pub unsafe trait IsInit: InitStatus {}
101
102// SAFETY: `Init` represents initialised
103unsafe impl<T> IsInit for Init<T>
104where
105	T: ?Sized
106{}
107
108/// Types that can be used safely for slots of type `T`
109///
110/// For example, if we have an API that is expecting a string, we would
111/// implement this trait for string types.
112pub unsafe trait Slot<S>
113where
114	Self: Sized
115{
116	type TypeMarker: TypeMarker;
117
118	/// Output type of reading from a slot previously written to (can be anything)
119	type Result: Sized;
120
121	/// Writes `self` into `slot`, doing as little work as needed
122	///
123	/// Work should be deferred to [`read`], if possible.
124	///
125	/// # Safety
126	///
127	/// Implementors must store a value into `slot`, that [`read`]
128	/// can read back later. [`read`] is allowed to rely on the fact that
129	/// something has been written.
130	///
131	/// It may be undesireable to call [`write`] twice on the same `slot`,
132	/// but even with that, there is no _strict_ requirement that callers only
133	/// call [`write`] once.
134	///
135	/// [`read`]: Slot::read
136	/// [`write`]: Slot::write
137	unsafe fn write(self, slot: &mut S);
138
139	/// Reads back what was written to `slot` in [`write`], then processes it
140	/// into the read output type as necessary
141	///
142	/// # Safety
143	///
144	/// Implementors can assume that [`write`] has been called on `slot` and a
145	/// value has been written as expected.
146	///
147	/// Callers must call [`write`] on this slot first, before passing it
148	/// to this function.
149	///
150	/// [`write`]: Slot::write
151	unsafe fn read(slot: S) -> Self::Result;
152
153	/// Converts the read output type into a reference of type
154	/// [`&ExternAny`](crate::ExternAny)
155	///
156	/// This function is used so implementors can return non reference types.
157	/// Trait consumers would then take ownership of the provided output, and
158	/// use this function to get a reference type [`&ExternAny`](crate::ExternAny)
159	/// from it.
160	fn as_ref(result: &Self::Result) -> &crate::ExternAny;
161}
162
163/// [`PhantomData`] but invariant over `T` and marks the type as `!Send` and `!Sync`.
164///
165/// To construct values of this type, you still must use the expression
166/// `PhantomData`, as Rust doesn't like using type definitions as unit struct
167/// constructors.
168pub(crate) type PhantomDataBuilder<S> = PhantomData<(
169	// `S` invariant
170	fn(S) -> S,
171	// `!Send` and `!Sync`
172	*mut ()
173)>;
174
175/// [`PhantomData`] but invariant over `T`
176///
177/// To construct values of this type, you still must use the expression
178/// `PhantomData`, as Rust doesn't like using type definitions as unit struct
179/// constructors.
180pub(crate) type PhantomDataInvariant<T> = PhantomData<fn(T) -> T>;
181
182macro_rules! gen_struct {
183	{
184		$(#[$meta:meta])*
185		// name of "builder" struct
186		struct $struct_name_without_state:ident $struct_name:ident;
187
188		// generates deref impl if this is present
189		$(
190			deref $deref_type:ty;
191			// uses this expression to initialise the value on first deref
192			deref_value $deref_value:expr;
193		)?
194
195		// generates a different deref impl if this is present
196		// only this or the one above can be present, of course
197		$(untracked_deref $untracked_field_deref:ident: $untracked_field_deref_type:ty;)?
198
199		$(
200			field
201			// field name
202			$field:ident
203			// name of generated slot type (without generics etc)
204			$slot:ident;
205		)*
206
207		$(untracked_field $untracked_field:ident: $untracked_field_type:ty;)*
208	} => {
209		pub type $struct_name_without_state = $struct_name<'static, StateUninit>;
210
211		#[repr(transparent)]
212		pub struct $struct_name<'h, S: State> {
213			inner: Inner<'h>,
214			__marker: PhantomDataBuilder<S>
215		}
216
217		struct Inner<'h> {
218			__use_h: PhantomData<&'h ()>,
219			$(__deref: ::core::cell::UnsafeCell<::core::option::Option<$deref_type>>,)?
220			$($field: $slot<'h>,)*
221			$($untracked_field: $untracked_field_type),*
222		}
223
224		impl $struct_name<'static, StateUninit> {
225			/// # Safety
226			///
227			/// This is an autogenerated function that should only be usedd internally.
228			/// It might have unknown preconditions on the values that can be passed
229			/// in. Because of this, it has been conservatively marked unsafe.
230			#[inline(always)]
231			const unsafe fn __new(
232				$($untracked_field: $untracked_field_type),*
233			) -> Self {
234				Self {
235					inner: Inner {
236						__use_h: PhantomData,
237						// its `None::<$deref_type>` and not just `None` so rust knows
238						// to base the presence of this field on it
239						$(__deref: ::core::cell::UnsafeCell::new(None::<$deref_type>),)?
240						$($field: $slot::uninit(),)*
241						$($untracked_field),*
242					},
243					__marker: PhantomData
244				}
245			}
246		}
247
248		$(
249			impl<'h, S> ::core::ops::Deref for $struct_name<'h, S>
250			where
251				S: State
252			{
253				type Target = $deref_type;
254
255				#[inline(always)]
256				fn deref(&self) -> &$deref_type {
257					// SAFETY: we are not thread safe so taking mut ref like
258					// this of the inner value of UnsafeCell temporarily is fine,
259					// we won't ever have two mut references (the closure in the call
260					// to `get_or_insert_with` can't access `self`)
261					unsafe {
262						(*self.inner.__deref.get())
263							.get_or_insert_with(|| $deref_value)
264					}
265				}
266			}
267		)?
268
269		$(
270			impl<'h, S> ::core::ops::Deref for $struct_name<'h, S>
271			where
272				S: State
273			{
274				type Target = $untracked_field_deref_type;
275
276				#[inline(always)]
277				fn deref(&self) -> &$untracked_field_deref_type {
278					&self.inner.$untracked_field_deref
279				}
280			}
281		)?
282	};
283}
284pub(crate) use gen_struct;
285
286macro_rules! gen_slot {
287	{
288		$(#[$meta:meta])*
289		// name of slot struct
290		slot $slot:ident;
291		$(
292			field
293			// name of field
294			$field:ident
295			// type of the field to store (can use 'h lifetime in the type)
296			$field_type:ty;
297		)*
298	} => {
299		$(#[$meta])*
300		pub union $slot<'h> {
301			uninit: (),
302			any: &'h ExternAny,
303			$($field: ::core::mem::ManuallyDrop<$field_type>),*
304		}
305
306		impl $slot<'static> {
307			#[inline(always)]
308			pub(crate) const fn uninit() -> Self {
309				// totally not stolen from MaybeUninit uwu
310				Self { uninit: () }
311			}
312		}
313	};
314}
315pub(crate) use gen_slot;
316
317macro_rules! gen_slot_impl {
318	// generates slot impl
319	{
320		$(#[$meta:meta])*
321		slot $slot:ident;
322		impl$({ $($generics:tt)* })? $impl_type:ty;
323
324		$($stuff:tt)*
325	} => {
326		unsafe impl<'h $(, $($generics)*)?> Slot<$slot<'h>> for $impl_type {
327			gen_slot_impl! {
328				@impl
329				slot $slot;
330				impl $impl_type;
331
332				$($stuff)*
333			}
334		}
335	};
336
337	// Slot::Result
338	{
339		@impl
340		slot $slot:ident;
341		impl $impl_type:ty;
342
343		result $result_type:ty;
344
345		$($stuff:tt)*
346	} => {
347		type Result = $result_type;
348
349		gen_slot_impl! {
350			@impl
351			slot $slot;
352			impl $impl_type;
353
354			$($stuff)*
355		}
356	};
357
358	// Slot::TypeMarker = ()
359	{
360		@impl
361		slot $slot:ident;
362		impl $impl_type:ty;
363
364		no_type_marker;
365
366		$($stuff:tt)*
367	} => {
368		type TypeMarker = ();
369
370		gen_slot_impl! {
371			@impl
372			slot $slot;
373			impl $impl_type;
374
375			$($stuff)*
376		}
377	};
378
379	// Slot::TypeMarker
380	{
381		@impl
382		slot $slot:ident;
383		impl $impl_type:ty;
384
385		type_marker $type_marker:ty;
386
387		$($stuff:tt)*
388	} => {
389		type TypeMarker = $type_marker;
390
391		gen_slot_impl! {
392			@impl
393			slot $slot;
394			impl $impl_type;
395
396			$($stuff)*
397		}
398	};
399
400	{
401		@impl
402		slot $slot:ident;
403		impl $impl_type:ty;
404
405		no_type_marker;
406
407		$($stuff:tt)*
408	} => {
409		type TypeMarker = ();
410
411		gen_slot_impl! {
412			@impl
413			slot $slot;
414			impl $impl_type;
415
416			$($stuff)*
417		}
418	};
419
420	// Slot::write
421	{
422		@impl
423		slot $slot:ident;
424		impl $impl_type:ty;
425
426		write($self:ident, $write_slot:ident) {
427			$($write_impl:tt)*
428		}
429
430		$($stuff:tt)*
431	} => {
432		#[inline(always)]
433		unsafe fn write($self, $write_slot: &mut $slot<'h>) {
434			$($write_impl)*
435		}
436
437		gen_slot_impl! {
438			@impl
439			slot $slot;
440			impl $impl_type;
441
442			$($stuff)*
443		}
444	};
445
446	// Slot::read
447	{
448		@impl
449		slot $slot:ident;
450		impl $impl_type:ty;
451
452		read($read_slot:ident) {
453			$($read_impl:tt)*
454		}
455
456		$($stuff:tt)*
457	} => {
458		#[inline(always)]
459		unsafe fn read($read_slot: $slot<'h>) -> Self::Result {
460			$($read_impl)*
461		}
462
463		gen_slot_impl! {
464			@impl
465			slot $slot;
466			impl $impl_type;
467
468			$($stuff)*
469		}
470	};
471
472	// Slot::as_ref
473	{
474		@impl
475		slot $slot:ident;
476		impl $impl_type:ty;
477
478		as_ref($as_ref_result:ident) {
479			$($as_ref_impl:tt)*
480		}
481
482		$($stuff:tt)*
483	} => {
484		#[inline(always)]
485		fn as_ref($as_ref_result: &Self::Result) -> &ExternAny {
486			$($as_ref_impl)*
487		}
488
489		gen_slot_impl! {
490			@impl
491			slot $slot;
492			impl $impl_type;
493
494			$($stuff)*
495		}
496	};
497
498	// *slot = Slot { field: self }
499	// does rely on simple assignment syntax to the field
500	// (autoderef if needed etc.)
501	{
502		@impl
503		slot $slot:ident;
504		impl $impl_type:ty;
505
506		simple_w $field:ident;
507
508		$($stuff:tt)*
509	} => {
510		gen_slot_impl! {
511			@impl
512			slot $slot;
513			impl $impl_type;
514
515			write(self, slot) {
516				*slot = $slot { $field: self }
517			}
518
519			$($stuff)*
520		}
521	};
522
523	// simple_w, additionally just reading the slot field in read
524	// unsafe { slot.field }
525	{
526		@impl
527		slot $slot:ident;
528		impl $impl_type:ty;
529
530		simple_rw $field:ident;
531
532		$($stuff:tt)*
533	} => {
534		gen_slot_impl! {
535			@impl
536			slot $slot;
537			impl $impl_type;
538
539			simple_w $field;
540
541			read(slot) {
542				unsafe { slot.$field }
543			}
544
545			$($stuff)*
546		}
547	};
548
549	// implements Slot::as_ref via just returning result
550	// (autoderef if needed etc.)
551	{
552		@impl
553		slot $slot:ident;
554		impl $impl_type:ty;
555
556		autoderef;
557
558		$($stuff:tt)*
559	} => {
560		gen_slot_impl! {
561			@impl
562			slot $slot;
563			impl $impl_type;
564
565			as_ref(result) { result }
566
567			$($stuff)*
568		}
569	};
570
571	{
572		@impl
573		slot $slot:ident;
574		impl $impl_type:ty;
575	} => { /* empty uwu */ };
576}
577pub(crate) use gen_slot_impl;
578
579/// macro for the boilerplate of calling `Slot::read`
580/// followed by conversion to `&JsValue`
581///
582/// # Examples
583///
584/// ```ignore
585/// unsafe {
586///    unsafe_read_slots! {
587///       self
588///       value: Value
589///       value2: Value2
590///       cheese: Cheese
591///    }
592/// }
593/// ```
594///
595/// Expands to:
596///
597/// ```ignore
598/// unsafe {
599///    let value = Value::read(self.inner.value);
600///    let value = value.as_ref().as_js_value();
601///    let value2 = Value2::read(self.inner.value2);
602///    let value2 = value2.as_ref().as_js_value();
603///    let cheese = Cheese::read(self.inner.cheese);
604///    let cheese = cheese.as_ref().as_js_value();
605/// }
606/// ```
607///
608/// Well... not quite, but, good enough for purposes of demonstration.
609///
610/// # Safety
611///
612/// The fields/slots you pass in must actually be valid for reading.
613macro_rules! unsafe_read_slots {
614	{
615		$self:ident
616		$($ident:ident: $ty:ident)*
617	} => {
618		$(
619			// SAFETY: caller guarantees this slot is valid to read from
620			let $ident = unsafe { $ty::read($self.inner.$ident) };
621			let $ident = $ty::as_ref(&$ident).as_js_value();
622		)*
623	}
624}
625pub(crate) use unsafe_read_slots;
626
627macro_rules! gen_state {
628	{
629		$(
630			$(#[$state_meta:meta])*
631			state
632		)?
633
634		$(
635			$(#[$container_meta:meta])*
636			container
637		)?
638
639		$(
640			$(#[$uninit_meta:meta])*
641			uninit
642		)?
643
644		$(
645			field $field:ident;
646			init $field_init:ident;
647		)*
648	} => {
649		$($(#[$state_meta])*)?
650		pub trait State {
651			$(
652				type $field: InitStatus;
653				type $field_init<T: ?Sized, M: ?Sized + TypeMarker>: State;
654			)*
655		}
656
657		#[allow(
658			unused_parens,
659			reason = "automatically generated"
660		)]
661		#[expect(
662			clippy::allow_attributes,
663			reason = "automatically generated (lint might not actually trigger, depending on input)"
664		)]
665		$($(#[$container_meta])*)?
666		pub struct StateContainer<$($field),*> {
667			__marker: PhantomDataInvariant<(
668				$($field),*
669			)>
670		}
671
672		gen_state! {
673			@impl gen_uninit
674			$(
675				$(#[$uninit_meta])*
676				uninit
677			)?
678
679			{}
680			{ $($field)* }
681		}
682
683		impl<$(
684			$field: InitStatus
685		),*> State for StateContainer<$($field),*> {
686			gen_state! {
687				@impl state_init_types
688				{}
689				{}
690				{ $($field $field_init)* }
691			}
692		}
693	};
694
695	{
696		@impl gen_uninit
697		$(
698			$(#[$uninit_meta:meta])*
699			uninit
700		)?
701
702		{ $($uninit_type:ident)* }
703		{
704			$field:ident
705			$($field_rest:ident)*
706		}
707	} => {
708		gen_state! {
709			@impl gen_uninit
710			$(
711				$(#[$uninit_meta])*
712				uninit
713			)?
714
715			{
716				$($uninit_type)*
717				Uninit
718			}
719			{ $($field_rest)* }
720		}
721	};
722
723	{
724		@impl gen_uninit
725		$(
726			$(#[$uninit_meta:meta])*
727			uninit
728		)?
729
730		{ $($uninit_type:ident)* }
731		{}
732	} => {
733		pub type StateUninit = StateContainer<
734			$($uninit_type),*
735		>;
736	};
737
738	{
739		@impl state_init_types
740		{}
741		{}
742		{}
743	} => {};
744
745	{
746		@impl state_init_types
747		{}
748		{}
749		{
750			$field_next:ident $field_init_next:ident
751			$($field_rest:ident $field_init_rest:ident)*
752		}
753	} => {
754		gen_state! {
755			@impl state_init_types
756			{}
757			{ $field_next $field_init_next }
758			{ $($field_rest $field_init_rest)* }
759		}
760	};
761
762	{
763		@impl state_init_types
764		{ $($field_prev:ident $field_init_prev:ident)* }
765		{ $field:ident $field_init:ident }
766		{
767			$field_next:ident $field_init_next:ident
768			$($field_rest:ident $field_init_rest:ident)*
769		}
770	} => {
771		type $field = $field;
772		type $field_init<T: ?Sized, M: ?Sized + TypeMarker> = StateContainer<
773			$($field_prev,)*
774			Init<T, M>,
775			$field_next,
776			$($field_rest),*
777		>;
778
779		gen_state! {
780			@impl state_init_types
781			{
782				$($field_prev $field_init_prev)*
783				$field $field_init
784			}
785			{ $field_next $field_init_next }
786			{ $($field_rest $field_init_rest)* }
787		}
788	};
789
790	{
791		@impl state_init_types
792		{ $($field_prev:ident $field_init_prev:ident)* }
793		{ $field:ident $field_init:ident }
794		{}
795	} => {
796		type $field = $field;
797		type $field_init<T: ?Sized, M: ?Sized + TypeMarker> = StateContainer<
798			$($field_prev,)*
799			Init<T, M>
800		>;
801	};
802}
803pub(crate) use gen_state;
804
805macro_rules! gen_builder_fns {
806	{
807		struct $struct_name:ident;
808
809		$(
810			state $field_state:ident;
811			init $field_init:ident;
812			slot $slot:ident;
813			$(extra_bounds { $($extra_bounds:tt)* };)?
814
815			$(#[$meta:meta])*
816			field $field:ident $($no_lifetime:ident)?;
817		)*
818	} => {
819		impl<'h, S: State> $struct_name<'h, S> {
820			gen_change_state!($struct_name);
821
822			$(
823				gen_builder_fn! {
824					struct $struct_name;
825
826					state $field_state;
827					init $field_init;
828					slot $slot;
829					$(extra_bounds { $($extra_bounds)* };)?
830
831					$(#[$meta:meta])*
832					field $field $($no_lifetime)?;
833				}
834			)*
835		}
836	}
837}
838pub(crate) use gen_builder_fns;
839
840macro_rules! gen_builder_fn {
841	{
842		struct $struct_name:ident;
843
844		state $field_state:ident;
845		init $field_init:ident;
846		slot $slot:ident;
847		$(extra_bounds { $($extra_bounds:tt)* };)?
848
849		$(#[$meta:meta])*
850		field $field:ident;
851	} => {
852		#[inline(always)]
853		$(#[$meta])*
854		pub fn $field<T>(
855			self,
856			$field: T
857		) -> $struct_name<'h, S::$field_init<T, T::TypeMarker>>
858		where
859			S::$field_state: IsUninit,
860			T: Slot<$slot<'h>>,
861			$($($extra_bounds)*)?
862		{
863			unsafe { self.change_state(|b| $field.write(&mut b.inner.$field)) }
864		}
865	};
866}
867pub(crate) use gen_builder_fn;
868
869macro_rules! gen_change_state {
870	($struct_name:ident) => {
871		#[inline(always)]
872		unsafe fn change_state<'h2, S2, F>(self, f: F) -> $struct_name<'h2, S2>
873		where
874			'h: 'h2,
875			S2: State,
876			F: FnOnce(&mut $struct_name<'h2, S2>)
877		{
878			let mut changed = $struct_name {
879				inner: self.inner,
880				__marker: PhantomData
881			};
882
883			f(&mut changed);
884			changed
885		}
886	};
887}
888pub(crate) use gen_change_state;
889
890macro_rules! gen_call_fn {
891	{
892		struct $struct_name:ident;
893		raw_call $raw_call:expr;
894		return $return_type:ty;
895
896		$($rest:tt)*
897	} => {
898		gen_call_fn! {
899			@impl nom_fields
900			struct $struct_name;
901			raw_call $raw_call;
902			return $return_type;
903
904			fn_name call_fn;
905
906			fields {}
907
908			$($rest)*
909		}
910	};
911
912	{
913		@impl nom_fields
914		struct $struct_name:ident;
915		raw_call $raw_call:expr;
916		return $return_type:ty;
917
918		$(#[$meta:meta])*
919		fn_name $fn_name:ident;
920
921		fields { $($fields:tt)* }
922
923		field $field_name:ident;
924		state $field_state:ident;
925		init Init<$slot:ident>;
926
927		$($stuff:tt)*
928	} => {
929		gen_call_fn! {
930			@impl nom_fields
931			struct $struct_name;
932			raw_call $raw_call;
933			return $return_type;
934
935			$(#[$meta])*
936			fn_name $fn_name;
937
938			fields {
939				$($fields)*
940
941				field
942				{ $field_state: Slot<$slot<'h>>, }
943				{ Init<$field_state> }
944				{ $field_name: $field_state }
945				{}
946			}
947
948			$($stuff)*
949		}
950	};
951
952	{
953		@impl nom_fields
954		struct $struct_name:ident;
955		raw_call $raw_call:expr;
956		return $return_type:ty;
957
958		$(#[$meta:meta])*
959		fn_name $fn_name:ident;
960
961		fields { $($fields:tt)* }
962
963		field $field_name:ident;
964		state $field_state:ident;
965		init Init<$slot:ident, $general_type:ty>;
966
967		$($stuff:tt)*
968	} => {
969		gen_call_fn! {
970			@impl nom_fields
971			struct $struct_name;
972			raw_call $raw_call;
973			return $return_type;
974
975			$(#[$meta])*
976			fn_name $fn_name;
977
978			fields {
979				$($fields)*
980
981				field
982				{ $field_state: Slot<$slot<'h>>, }
983				{ Init<$field_state, $general_type> }
984				{ $field_name: $field_state }
985				{}
986			}
987
988			$($stuff)*
989		}
990	};
991
992	{
993		@impl nom_fields
994		struct $struct_name:ident;
995		raw_call $raw_call:expr;
996		return $return_type:ty;
997
998		$(#[$meta:meta])*
999		fn_name $fn_name:ident;
1000
1001		fields { $($fields:tt)* }
1002
1003		field $field_name:ident;
1004		state $field_state:ident;
1005		init Init<$slot:ident, any $general_type:ident>;
1006
1007		$($stuff:tt)*
1008	} => {
1009		gen_call_fn! {
1010			@impl nom_fields
1011			struct $struct_name;
1012			raw_call $raw_call;
1013			return $return_type;
1014
1015			$(#[$meta])*
1016			fn_name $fn_name;
1017
1018			fields {
1019				$($fields)*
1020
1021				field
1022				{ $field_state: Slot<$slot<'h>>, $general_type: TypeMarker, }
1023				{ Init<$field_state, $general_type> }
1024				{ $field_name: $field_state }
1025				{}
1026			}
1027
1028			$($stuff)*
1029		}
1030	};
1031
1032	{
1033		@impl nom_fields
1034		struct $struct_name:ident;
1035		raw_call $raw_call:expr;
1036		return $return_type:ty;
1037
1038		$(#[$meta:meta])*
1039		fn_name $fn_name:ident;
1040
1041		fields { $($fields:tt)* }
1042
1043		field $field_name:ident;
1044		state $field_state:ident;
1045		init Uninit;
1046
1047		$($stuff:tt)*
1048	} => {
1049		gen_call_fn! {
1050			@impl nom_fields
1051			struct $struct_name;
1052			raw_call $raw_call;
1053			return $return_type;
1054
1055			$(#[$meta])*
1056			fn_name $fn_name;
1057
1058			fields {
1059				$($fields)*
1060
1061				field
1062				{}
1063				{ Uninit }
1064				{}
1065				{ $field_name }
1066			}
1067
1068			$($stuff)*
1069		}
1070	};
1071
1072	{
1073		@impl nom_fields
1074		struct $struct_name:ident;
1075		raw_call $raw_call:expr;
1076		return $return_type:ty;
1077
1078		$(#[$old_meta:meta])*
1079		fn_name $old_fn_name:ident;
1080
1081		fields { $($fields:tt)* }
1082
1083		$(#[$meta:meta])*
1084		fn;
1085
1086		$($stuff:tt)*
1087	} => {
1088		gen_call_fn! {
1089			@impl nom_fields
1090			struct $struct_name;
1091			raw_call $raw_call;
1092			return $return_type;
1093
1094			$(#[$old_meta])*
1095			$(#[$meta])*
1096			fn_name $old_fn_name;
1097
1098			fields { $($fields)* }
1099
1100			$($stuff)*
1101		}
1102	};
1103
1104	{
1105		@impl nom_fields
1106		struct $struct_name:ident;
1107		raw_call $raw_call:expr;
1108		return $return_type:ty;
1109
1110		$(#[$old_meta:meta])*
1111		fn_name $old_fn_name:ident;
1112
1113		fields { $($fields:tt)* }
1114
1115		$(#[$meta:meta])*
1116		fn $fn_name:ident;
1117
1118		$($stuff:tt)*
1119	} => {
1120		gen_call_fn! {
1121			@impl nom_fields
1122			struct $struct_name;
1123			raw_call $raw_call;
1124			return $return_type;
1125
1126			$(#[$old_meta])*
1127			$(#[$meta])*
1128			fn_name $fn_name;
1129
1130			fields { $($fields)* }
1131
1132			$($stuff)*
1133		}
1134	};
1135
1136	{
1137		@impl nom_fields
1138		struct $struct_name:ident;
1139		raw_call $raw_call:expr;
1140		return $return_type:ty;
1141
1142		$(#[$meta:meta])*
1143		fn_name $fn_name:ident;
1144
1145		fields {
1146			$(
1147				field
1148				{ $($impl_param:tt)* }
1149				{ $($struct_param:tt)* }
1150				{ $($unsafe_read_slots_input:tt)* }
1151				{ $($unused_fields:tt)* }
1152			)*
1153		}
1154	} => {
1155		impl<
1156			'h,
1157			$($($impl_param)*)*
1158		> $struct_name<'h, StateContainer<
1159			$($($struct_param)*),*
1160		>> {
1161			#[inline(always)]
1162			$(#[$meta])*
1163			pub fn $fn_name(self) -> $return_type {
1164				// SAFETY: provided slots are valid for reading,
1165				// enforced by type system
1166				unsafe_read_slots! {
1167					self
1168					$($($unsafe_read_slots_input)*)*
1169				}
1170
1171				$($(
1172					#[allow(
1173						clippy::drop_non_drop,
1174						reason = "automatically generated"
1175					)]
1176					#[expect(
1177						clippy::allow_attributes,
1178						reason = "automatically generated (lint might not actually trigger, depending on input)"
1179					)]
1180					drop(self.inner.$unused_fields);
1181				)*)*
1182
1183				$raw_call
1184			}
1185		}
1186	};
1187}
1188pub(crate) use gen_call_fn;