wiwi_chain/
lib.rs

1use self::sealed::*;
2
3pub use self::array::{ ArrayChain, ArrayMutChain };
4pub use self::string::{ StringChain, StringMutChain };
5pub use self::vec::{ VecChain, VecMutChain };
6
7mod array;
8mod string;
9mod vec;
10
11pub trait Chain: Sized + ChainSealed {
12	type Inner: ChainInner<Chain = Self>;
13
14	fn from_inner(inner: Self::Inner) -> Self;
15
16	#[inline]
17	fn into_inner(self) -> Self::Inner {
18		Self::Inner::from_chain(self)
19	}
20
21	/// Takes a closure that is called, passing in a reference to the inner value
22	///
23	/// This is useful for if there is something we have not implemented, or you
24	/// otherwise need to borrow the inner struct for something, but are in the
25	/// middle of some chain. It lets you do otherwise nonchainable operations
26	/// inline with other chaining operations, so no need to break the chain c:
27	///
28	/// # Examples
29	///
30	// todo fix and unignore this
31	/// ```ignore
32	/// # use wiwi_chain::{ Chain as _, VecChain };
33	/// let chain = VecChain::<usize>::new();
34	///
35	/// // let's pretend `push` and `reserve` don't already have chainable versions...
36	/// let chain = chain
37	///    .with_inner(|v| v.reserve(10))
38	///    .with_inner(|v| v.push(1))
39	///    .with_inner(|v| v.push(2));
40	///
41	/// assert!(chain.as_inner().len() == 2);
42	/// assert!(chain.as_inner().capacity() >= 10);
43	/// ```
44	fn with_inner(self, f: impl FnOnce(&mut Self::Inner)) -> Self;
45}
46
47pub trait ChainInner: Sized + ChainInnerSealed {
48	type Chain: Chain<Inner = Self>;
49
50	fn from_chain(chain: Self::Chain) -> Self;
51
52	#[inline]
53	fn into_chain(self) -> Self::Chain {
54		Self::Chain::from_inner(self)
55	}
56}
57
58/// Trait implemented on chains and their inner types, allowing you to get a reference
59/// to the inner type regardless of if the chain or the inner type is passed in
60pub trait ChainConversions
61where
62	Self: Sized + ChainConversionsSealed
63{
64	type Inner: Sized;
65	type MutChain<'mut_chain>: Sized
66	where
67		Self: 'mut_chain;
68
69	fn as_inner(&self) -> &Self::Inner;
70	fn as_inner_mut(&mut self) -> &mut Self::Inner;
71	fn as_mut_chain(&mut self) -> Self::MutChain<'_>;
72}
73
74impl<T> ChainConversions for &mut T
75where
76	T: ChainConversions
77{
78	type Inner = T::Inner;
79	type MutChain<'mut_chain> = T::MutChain<'mut_chain>
80	where
81		Self: 'mut_chain;
82
83	#[inline]
84	fn as_inner(&self) -> &Self::Inner {
85		(**self).as_inner()
86	}
87
88	#[inline]
89	fn as_inner_mut(&mut self) -> &mut Self::Inner {
90		(**self).as_inner_mut()
91	}
92
93	#[inline]
94	fn as_mut_chain(&mut self) -> Self::MutChain<'_> {
95		(**self).as_mut_chain()
96	}
97}
98
99impl<T> ChainConversionsSealed for &mut T
100where
101	T: ChainConversionsSealed
102{}
103
104pub trait WithSelf: Sized {
105	/// Takes ownership of the value, passing a mutable reference of it to a
106	/// closure, then returning ownership of the value again
107	#[inline]
108	fn with_self<Void>(mut self, f: impl FnOnce(&mut Self) -> Void) -> Self {
109		let _ = f(&mut self);
110		self
111	}
112}
113
114impl<T> WithSelf for T {}
115
116/// # Safety
117///
118/// By using this trait, implementors of functions are promising to call
119/// [`write`](Output::write), so that when the function returns, there is a
120/// value written to the output. For example, users can pass a reference to
121/// [`MaybeUninit`](core::mem::MaybeUninit) and rely on the fact that it got
122/// initialised to safely call [`assume_init`](core::mem::MaybeUninit::assume_init).
123///
124/// idk how to enforce the above properly using unsafe etc.
125pub unsafe trait Output<T>: Sized + OutputSealed<T> {
126	/// Stores a value
127	fn write(self, item: T);
128}
129
130// SAFETY: we write once to `self`
131unsafe impl<T> Output<T> for &mut T {
132	#[expect(
133		clippy::inline_always,
134		reason = "same as MaybeUninit::write"
135	)]
136	#[inline(always)]
137	fn write(self, item: T) {
138		*self = item;
139	}
140}
141impl<T> OutputSealed<T> for &mut T {}
142
143// SAFETY: we write once to `self`
144unsafe impl<T> Output<T> for &mut Option<T> {
145	#[expect(
146		clippy::inline_always,
147		reason = "same as MaybeUninit::write"
148	)]
149	#[inline(always)]
150	fn write(self, item: T) {
151		*self = Some(item);
152	}
153}
154impl<T> OutputSealed<T> for &mut Option<T> {}
155
156// SAFETY: we write once to `self`
157unsafe impl<T> Output<T> for &mut core::mem::MaybeUninit<T> {
158	#[expect(
159		clippy::inline_always,
160		reason = "same as MaybeUninit::write"
161	)]
162	#[inline(always)]
163	fn write(self, item: T) {
164		self.write(item);
165	}
166}
167impl<T> OutputSealed<T> for &mut core::mem::MaybeUninit<T> {}
168
169/// Tool for helping to debug [`Output`] trait usage in debug mode (if `out` is
170/// not written to, the function will panic)
171///
172/// This function should optimise out to a no-op in release mode.
173#[inline]
174pub fn out_dbg<T, O: Output<T>>(out: O) -> OutputDebug<T, O> {
175	OutputDebug {
176		inner: out,
177		__marker: std::marker::PhantomData
178	}
179}
180
181#[repr(transparent)]
182pub struct OutputDebug<T, O>
183where
184	O: Output<T>
185{
186	inner: O,
187	__marker: core::marker::PhantomData<fn(T)>
188}
189
190impl<T, O> OutputDebug<T, O>
191where
192	O: Output<T>
193{
194	/// Unwraps self and returns the inner output (without ever panicking)
195	#[inline]
196	pub fn into_inner(self) -> O {
197		// in cfg(debug_assertions), we have Drop impl,
198		// so we need to do a funny to get `inner` out
199		#[cfg(debug_assertions)]
200		let inner = {
201			let this = core::mem::ManuallyDrop::new(self);
202
203			// SAFETY: ManuallyDrop above prevents double drops
204			unsafe { core::ptr::read(&raw const this.inner) }
205		};
206
207		// in not(cfg(debug_assertions)), we don't have
208		// Drop impl, so we can just normally move it out
209		#[cfg(not(debug_assertions))]
210		let inner = self.inner;
211
212		inner
213	}
214}
215
216// SAFETY: we write once to `self`
217unsafe impl<T, O> Output<T> for OutputDebug<T, O>
218where
219	O: Output<T>
220{
221	#[inline]
222	fn write(self, item: T) {
223		self.into_inner().write(item);
224	}
225}
226
227impl<T, O> OutputSealed<T> for OutputDebug<T, O>
228where
229	O: Output<T>
230{}
231
232#[cfg(debug_assertions)]
233impl<T, O> Drop for OutputDebug<T, O>
234where
235	O: Output<T>
236{
237	#[inline]
238	fn drop(&mut self) {
239		// writing to this slot will prevent this panic from being called (via ManuallyDrop)
240		// additionally this drop impl only is enabled if debug assertions is enabled
241		panic!("`write` not called on created instance of `Output` (this is probably a bug)")
242	}
243}
244
245macro_rules! decl_chain {
246	{
247		$(#[$meta:meta])*
248		struct $chain:ident;
249		inner $inner:ty;
250	} => {
251		$crate::decl_chain! {
252			$(#[$meta])*
253			struct $chain[];
254			impl[] $chain;
255			inner $inner;
256		}
257	};
258
259	{
260		$(#[$meta:meta])*
261		struct $chain:ident[$($chain_decl_generics:tt)*];
262		impl[$($chain_impl_generics:tt)*] $chain_impl:ty;
263		$(where { $($where:tt)* };)?
264		inner $inner:ty;
265	} => {
266		$(#[$meta])*
267		#[must_use = "a chain always takes ownership of itself, performs the operation, then returns itself again"]
268		#[repr(transparent)]
269		pub struct $chain<$($chain_decl_generics)*>
270		$(where $($where)*)?
271		{
272			__inner: $inner
273		}
274
275		impl<$($chain_impl_generics)*> $crate::Chain for $chain_impl
276		$(where $($where)*)?
277		{
278			type Inner = $inner;
279
280			#[inline]
281			fn from_inner(inner: $inner) -> Self {
282				Self { __inner: inner }
283			}
284
285			#[inline]
286			fn with_inner(mut self, f: impl FnOnce(&mut Self::Inner)) -> Self {
287				let _ = f(&mut self.__inner);
288				self
289			}
290		}
291
292		impl<$($chain_impl_generics)*> $crate::ChainInner for $inner
293		$(where $($where)*)?
294		{
295			type Chain = $chain_impl;
296
297			#[inline]
298			fn from_chain(chain: $chain_impl) -> Self {
299				chain.__inner
300			}
301		}
302
303		impl<$($chain_impl_generics)*> $crate::ChainSealed for $chain_impl
304		$(where $($where)*)?
305		{}
306
307		impl<$($chain_impl_generics)*> $crate::ChainInnerSealed for $inner
308		$(where $($where)*)?
309		{}
310
311		impl<$($chain_impl_generics)*> ::core::clone::Clone for $chain_impl
312		where
313			$inner: ::core::clone::Clone
314		{
315			#[inline]
316			fn clone(&self) -> Self {
317				let clone = <$inner as ::core::clone::Clone>::clone(&self.__inner);
318				<Self as $crate::Chain>::from_inner(clone)
319			}
320
321			#[inline]
322			fn clone_from(&mut self, other: &Self) {
323				<$inner as ::core::clone::Clone>::clone_from(
324					&mut self.__inner,
325					&other.__inner
326				);
327			}
328		}
329
330		impl<$($chain_impl_generics)*> ::core::default::Default for $chain_impl
331		where
332			$inner: ::core::default::Default
333		{
334			#[inline]
335			fn default() -> Self {
336				let default = <$inner as ::core::default::Default>::default();
337				<Self as $crate::Chain>::from_inner(default)
338			}
339		}
340
341		// todo this doesn't compile because `String: Copy` is a "trivial bound"
342		// https://github.com/rust-lang/rust/issues/48214
343		// smh
344		//
345		// impl<$($chain_impl_generics)*> ::core::marker::Copy for $chain_impl
346		// where
347		// 	$inner: ::core::marker::Copy
348		// {}
349
350		// todo more standard traits?
351	};
352}
353use decl_chain;
354
355macro_rules! impl_chain_conversions {
356	{
357		impl chain [$($impl_chain_generics:tt)*] $impl_chain:ty;
358		impl chain_mut [$($impl_chain_mut_generics:tt)*] $impl_chain_mut:ty;
359		impl inner [$($impl_inner_generics:tt)*] $impl_inner:ty;
360		type inner $inner_type:ty;
361		type mut_chain $mut_chain_type:ty;
362	} => {
363		impl<$($impl_chain_generics)*> $crate::ChainConversions for $impl_chain {
364			type Inner = $inner_type;
365			type MutChain<'mut_chain> = $mut_chain_type
366			where
367				Self: 'mut_chain;
368
369			#[inline]
370			fn as_inner(&self) -> &Self::Inner {
371				&self.__inner
372			}
373
374			#[inline]
375			fn as_inner_mut(&mut self) -> &mut Self::Inner {
376				&mut self.__inner
377			}
378
379			#[inline]
380			fn as_mut_chain(&mut self) -> Self::MutChain<'_> {
381				Self::MutChain { __inner: &mut self.__inner }
382			}
383		}
384
385		impl<$($impl_chain_mut_generics)*> $crate::ChainConversions for $impl_chain_mut {
386			type Inner = $inner_type;
387			type MutChain<'mut_chain> = $mut_chain_type
388			where
389				Self: 'mut_chain;
390
391			#[inline]
392			fn as_inner(&self) -> &Self::Inner {
393				self.__inner
394			}
395
396			#[inline]
397			fn as_inner_mut(&mut self) -> &mut Self::Inner {
398				self.__inner
399			}
400
401			#[inline]
402			fn as_mut_chain(&mut self) -> Self::MutChain<'_> {
403				Self::MutChain { __inner: self.__inner }
404			}
405		}
406
407		impl<$($impl_inner_generics)*> $crate::ChainConversions for $impl_inner {
408			type Inner = $inner_type;
409			type MutChain<'mut_chain> = $mut_chain_type
410			where
411				Self: 'mut_chain;
412
413			#[inline]
414			fn as_inner(&self) -> &Self::Inner {
415				self
416			}
417
418			#[inline]
419			fn as_inner_mut(&mut self) -> &mut Self::Inner {
420				self
421			}
422
423			#[inline]
424			fn as_mut_chain(&mut self) -> Self::MutChain<'_> {
425				Self::MutChain { __inner: self }
426			}
427		}
428
429		impl<$($impl_chain_generics)*> $crate::ChainConversionsSealed for $impl_chain {}
430		impl<$($impl_chain_mut_generics)*> $crate::ChainConversionsSealed for $impl_chain_mut {}
431		impl<$($impl_inner_generics)*> $crate::ChainConversionsSealed for $impl_inner {}
432	};
433}
434use impl_chain_conversions;
435
436macro_rules! chain_fns {
437	{
438		impl chain [$($impl_chain_generics:tt)*] $impl_chain:ty;
439		impl chain_mut [$($impl_chain_mut_generics:tt)*] $impl_chain_mut:ty;
440
441		$($stuff:tt)*
442	} => {
443		impl<$($impl_chain_generics)*> $impl_chain {
444			$crate::chain_fns! { @impl $($stuff)* }
445		}
446
447		impl<$($impl_chain_mut_generics)*> $impl_chain_mut {
448			$crate::chain_fns! { @impl $($stuff)* }
449		}
450	};
451
452	{
453		@impl
454		$(underlying_fn $underlying_fn:literal $(($underlying_fn_link_to:literal))?)?
455		$(#[$meta:meta])*
456		fn $fn_name:ident$([$($generics:tt)*])?
457		($inner:ident $($params:tt)*)
458		$(where { $($where:tt)* })?
459		{ $($impl:tt)* }
460
461		$($stuff:tt)*
462	} => {
463		#[inline]
464		#[warn(missing_docs)]
465		$(#[$meta])*
466		$(
467			#[doc = ""]
468			#[doc = concat!(
469				"See documentation for [`",
470				$underlying_fn,
471				"`]",
472				$(
473					"(",
474					$underlying_fn_link_to,
475					")",
476				)?
477				" for more details on the underlying function."
478			)]
479		)?
480		pub fn $fn_name$(<$($generics)*>)?(mut self $($params)*) -> Self
481		$(where $($where)*)?
482		{
483			let $inner = <Self as $crate::ChainConversions>::as_inner_mut(&mut self);
484			let _: () = { $($impl)* };
485			self
486		}
487
488		$crate::chain_fns! { @impl $($stuff)* }
489	};
490
491	{
492		@impl
493		$(underlying_fn $underlying_fn:literal $(($underlying_fn_link_to:literal))?)?
494		$(#[$meta:meta])*
495		unsafe fn $fn_name:ident$([$($generics:tt)*])?
496		($inner:ident $($params:tt)*)
497		$(where { $($where:tt)* })?
498		{ $($impl:tt)* }
499
500		$($stuff:tt)*
501	} => {
502		#[inline]
503		#[warn(missing_docs)]
504		$(#[$meta])*
505		$(
506			#[doc = ""]
507			#[doc = "# Safety"]
508			#[doc = ""]
509			#[doc = concat!(
510				"You must uphold safety invariants of [`",
511				$underlying_fn,
512				"`]",
513				$(
514					"(",
515					$underlying_fn_link_to,
516					")",
517				)?
518				"."
519			)]
520			#[doc = ""]
521			#[doc = concat!(
522				"See documentation for [`",
523				$underlying_fn,
524				"`]",
525				$(
526					"(",
527					$underlying_fn_link_to,
528					")",
529				)?
530				" for more details on the underlying function."
531			)]
532		)?
533		pub unsafe fn $fn_name$(<$($generics)*>)?(mut self $($params)*) -> Self
534		$(where $($where)*)?
535		{
536			let $inner = <Self as $crate::ChainConversions>::as_inner_mut(&mut self);
537			let _: () = { $($impl)* };
538			self
539		}
540
541		$crate::chain_fns! { @impl $($stuff)* }
542	};
543
544	{ @impl } => {};
545}
546use chain_fns;
547
548/// notouchie
549mod sealed {
550	/// notouchie
551	pub trait ChainSealed {}
552
553	/// notouchie
554	pub trait ChainInnerSealed {}
555
556	/// notouchie
557	pub trait OutputSealed<T> {}
558
559	/// notouchie
560	pub trait ChainConversionsSealed {}
561}