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#[inline]
172pub fn out_dbg<T, O: Output<T>>(out: O) -> OutputDebug<T, O> {
173	OutputDebug { inner: out, __marker: std::marker::PhantomData }
174}
175
176#[repr(transparent)]
177pub struct OutputDebug<T, O>
178where
179	O: Output<T>
180{
181	inner: O,
182	__marker: core::marker::PhantomData<fn(T)>
183}
184
185impl<T, O> OutputDebug<T, O>
186where
187	O: Output<T>
188{
189	#[inline]
190	pub fn into_inner(self) -> O {
191		// in cfg(debug_assertions), we have Drop impl,
192		// so we need to do a funny to get `inner` out
193		#[cfg(debug_assertions)]
194		let inner = {
195			let this = core::mem::ManuallyDrop::new(self);
196
197			// SAFETY: ManuallyDrop above prevents double drops
198			unsafe { core::ptr::read(&this.inner) }
199		};
200
201		// in not(cfg(debug_assertions)), we don't have
202		// Drop impl, so we can just normally move it out
203		#[cfg(not(debug_assertions))]
204		let inner = self.inner;
205
206		inner
207	}
208}
209
210// SAFETY: we write once to `self`
211unsafe impl<T, O> Output<T> for OutputDebug<T, O>
212where
213	O: Output<T>
214{
215	#[inline]
216	fn write(self, item: T) {
217		self.into_inner().write(item);
218	}
219}
220impl<T, O> OutputSealed<T> for OutputDebug<T, O>
221where
222	O: Output<T>
223{}
224
225#[cfg(debug_assertions)]
226impl<T, O> Drop for OutputDebug<T, O>
227where
228	O: Output<T>
229{
230	#[inline]
231	fn drop(&mut self) {
232		panic!("`write` not called on created instance of `Output` (this is probably a bug)")
233	}
234}
235
236macro_rules! decl_chain {
237	{
238		$(#[$meta:meta])*
239		struct $chain:ident;
240		inner $inner:ty;
241	} => {
242		$crate::decl_chain! {
243			$(#[$meta])*
244			struct $chain[];
245			impl[] $chain;
246			inner $inner;
247		}
248	};
249
250	{
251		$(#[$meta:meta])*
252		struct $chain:ident[$($chain_decl_generics:tt)*];
253		impl[$($chain_impl_generics:tt)*] $chain_impl:ty;
254		$(where { $($where:tt)* };)?
255		inner $inner:ty;
256	} => {
257		$(#[$meta])*
258		#[must_use = "a chain always takes ownership of itself, performs the operation, then returns itself again"]
259		#[repr(transparent)]
260		pub struct $chain<$($chain_decl_generics)*>
261		$(where $($where)*)?
262		{
263			__inner: $inner
264		}
265
266		impl<$($chain_impl_generics)*> $crate::Chain for $chain_impl
267		$(where $($where)*)?
268		{
269			type Inner = $inner;
270
271			#[inline]
272			fn from_inner(inner: $inner) -> Self {
273				Self { __inner: inner }
274			}
275
276			#[inline]
277			fn with_inner(mut self, f: impl FnOnce(&mut Self::Inner)) -> Self {
278				let _ = f(&mut self.__inner);
279				self
280			}
281		}
282
283		impl<$($chain_impl_generics)*> $crate::ChainInner for $inner
284		$(where $($where)*)?
285		{
286			type Chain = $chain_impl;
287
288			#[inline]
289			fn from_chain(chain: $chain_impl) -> Self {
290				chain.__inner
291			}
292		}
293
294		impl<$($chain_impl_generics)*> $crate::ChainSealed for $chain_impl
295		$(where $($where)*)?
296		{}
297
298		impl<$($chain_impl_generics)*> $crate::ChainInnerSealed for $inner
299		$(where $($where)*)?
300		{}
301
302		impl<$($chain_impl_generics)*> ::core::clone::Clone for $chain_impl
303		where
304			$inner: ::core::clone::Clone
305		{
306			#[inline]
307			fn clone(&self) -> Self {
308				let clone = <$inner as ::core::clone::Clone>::clone(&self.__inner);
309				<Self as $crate::Chain>::from_inner(clone)
310			}
311
312			#[inline]
313			fn clone_from(&mut self, other: &Self) {
314				<$inner as ::core::clone::Clone>::clone_from(
315					&mut self.__inner,
316					&other.__inner
317				);
318			}
319		}
320
321		impl<$($chain_impl_generics)*> ::core::default::Default for $chain_impl
322		where
323			$inner: ::core::default::Default
324		{
325			#[inline]
326			fn default() -> Self {
327				let default = <$inner as ::core::default::Default>::default();
328				<Self as $crate::Chain>::from_inner(default)
329			}
330		}
331
332		// todo this doesn't compile because `String: Copy` is a "trivial bound"
333		// https://github.com/rust-lang/rust/issues/48214
334		// smh
335		//
336		// impl<$($chain_impl_generics)*> ::core::marker::Copy for $chain_impl
337		// where
338		// 	$inner: ::core::marker::Copy
339		// {}
340
341		// todo more standard traits?
342	};
343}
344use decl_chain;
345
346macro_rules! impl_chain_conversions {
347	{
348		impl chain [$($impl_chain_generics:tt)*] $impl_chain:ty;
349		impl chain_mut [$($impl_chain_mut_generics:tt)*] $impl_chain_mut:ty;
350		impl inner [$($impl_inner_generics:tt)*] $impl_inner:ty;
351		type inner $inner_type:ty;
352		type mut_chain $mut_chain_type:ty;
353	} => {
354		impl<$($impl_chain_generics)*> $crate::ChainConversions for $impl_chain {
355			type Inner = $inner_type;
356			type MutChain<'mut_chain> = $mut_chain_type
357			where
358				Self: 'mut_chain;
359
360			#[inline]
361			fn as_inner(&self) -> &Self::Inner {
362				&self.__inner
363			}
364
365			#[inline]
366			fn as_inner_mut(&mut self) -> &mut Self::Inner {
367				&mut self.__inner
368			}
369
370			#[inline]
371			fn as_mut_chain(&mut self) -> Self::MutChain<'_> {
372				Self::MutChain { __inner: &mut self.__inner }
373			}
374		}
375
376		impl<$($impl_chain_mut_generics)*> $crate::ChainConversions for $impl_chain_mut {
377			type Inner = $inner_type;
378			type MutChain<'mut_chain> = $mut_chain_type
379			where
380				Self: 'mut_chain;
381
382			#[inline]
383			fn as_inner(&self) -> &Self::Inner {
384				self.__inner
385			}
386
387			#[inline]
388			fn as_inner_mut(&mut self) -> &mut Self::Inner {
389				self.__inner
390			}
391
392			#[inline]
393			fn as_mut_chain(&mut self) -> Self::MutChain<'_> {
394				Self::MutChain { __inner: self.__inner }
395			}
396		}
397
398		impl<$($impl_inner_generics)*> $crate::ChainConversions for $impl_inner {
399			type Inner = $inner_type;
400			type MutChain<'mut_chain> = $mut_chain_type
401			where
402				Self: 'mut_chain;
403
404			#[inline]
405			fn as_inner(&self) -> &Self::Inner {
406				self
407			}
408
409			#[inline]
410			fn as_inner_mut(&mut self) -> &mut Self::Inner {
411				self
412			}
413
414			#[inline]
415			fn as_mut_chain(&mut self) -> Self::MutChain<'_> {
416				Self::MutChain { __inner: self }
417			}
418		}
419
420		impl<$($impl_chain_generics)*> $crate::ChainConversionsSealed for $impl_chain {}
421		impl<$($impl_chain_mut_generics)*> $crate::ChainConversionsSealed for $impl_chain_mut {}
422		impl<$($impl_inner_generics)*> $crate::ChainConversionsSealed for $impl_inner {}
423	};
424}
425use impl_chain_conversions;
426
427macro_rules! chain_fns {
428	{
429		impl chain [$($impl_chain_generics:tt)*] $impl_chain:ty;
430		impl chain_mut [$($impl_chain_mut_generics:tt)*] $impl_chain_mut:ty;
431
432		$($stuff:tt)*
433	} => {
434		impl<$($impl_chain_generics)*> $impl_chain {
435			$crate::chain_fns! { @impl $($stuff)* }
436		}
437
438		impl<$($impl_chain_mut_generics)*> $impl_chain_mut {
439			$crate::chain_fns! { @impl $($stuff)* }
440		}
441	};
442
443	{
444		@impl
445		$(underlying_fn $underlying_fn:literal $(($underlying_fn_link_to:literal))?)?
446		$(#[$meta:meta])*
447		fn $fn_name:ident$([$($generics:tt)*])?
448		($inner:ident $($params:tt)*)
449		$(where { $($where:tt)* })?
450		{ $($impl:tt)* }
451
452		$($stuff:tt)*
453	} => {
454		#[inline]
455		#[warn(missing_docs)]
456		$(#[$meta])*
457		$(
458			#[doc = ""]
459			#[doc = concat!(
460				"See documentation for [`",
461				$underlying_fn,
462				"`]",
463				$(
464					"(",
465					$underlying_fn_link_to,
466					")",
467				)?
468				" for more details on the underlying function."
469			)]
470		)?
471		pub fn $fn_name$(<$($generics)*>)?(mut self $($params)*) -> Self
472		$(where $($where)*)?
473		{
474			let $inner = <Self as $crate::ChainConversions>::as_inner_mut(&mut self);
475			let _: () = { $($impl)* };
476			self
477		}
478
479		$crate::chain_fns! { @impl $($stuff)* }
480	};
481
482	{
483		@impl
484		$(underlying_fn $underlying_fn:literal $(($underlying_fn_link_to:literal))?)?
485		$(#[$meta:meta])*
486		unsafe fn $fn_name:ident$([$($generics:tt)*])?
487		($inner:ident $($params:tt)*)
488		$(where { $($where:tt)* })?
489		{ $($impl:tt)* }
490
491		$($stuff:tt)*
492	} => {
493		#[inline]
494		#[warn(missing_docs)]
495		$(#[$meta])*
496		$(
497			#[doc = ""]
498			#[doc = "# Safety"]
499			#[doc = ""]
500			#[doc = concat!(
501				"You must uphold safety invariants of [`",
502				$underlying_fn,
503				"`]",
504				$(
505					"(",
506					$underlying_fn_link_to,
507					")",
508				)?
509				"."
510			)]
511			#[doc = ""]
512			#[doc = concat!(
513				"See documentation for [`",
514				$underlying_fn,
515				"`]",
516				$(
517					"(",
518					$underlying_fn_link_to,
519					")",
520				)?
521				" for more details on the underlying function."
522			)]
523		)?
524		pub unsafe fn $fn_name$(<$($generics)*>)?(mut self $($params)*) -> Self
525		$(where $($where)*)?
526		{
527			let $inner = <Self as $crate::ChainConversions>::as_inner_mut(&mut self);
528			let _: () = { $($impl)* };
529			self
530		}
531
532		$crate::chain_fns! { @impl $($stuff)* }
533	};
534
535	{ @impl } => {};
536}
537use chain_fns;
538
539/// notouchie
540mod sealed {
541	/// notouchie
542	pub trait ChainSealed {}
543
544	/// notouchie
545	pub trait ChainInnerSealed {}
546
547	/// notouchie
548	pub trait OutputSealed<T> {}
549
550	/// notouchie
551	pub trait ChainConversionsSealed {}
552}