sdecay 0.2.0

Bindings for SandiaDecay C++ library, used to compute nuclide mixtures
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
//! Handling C++ types requires caution, because of possibly-defined move constructor. Since Rust types are always allowed to be moved, unless it's an `Unpin` type behind pinned pointer, representations of C++ types must contain `PhantomPinned` field and handled indirectly - behind a pinned smart pointer.
//!
//! This module defines [`Container`] trait, as well as multiple it's implementations, allowing us to handle C++ types without causing trouble.
//!
//! Unsafe: **YES**

#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use core::{mem::MaybeUninit, ops::Deref, pin::Pin};

/// Defines move constructor for the type
///
/// ### Copy types
///
/// All copy types have a trivial implementation via [`core::ptr::copy`]
///
/// Copy types are intended to have trivial move semantics, so in case your type DOES have special move constructor, make sure to make it `!Copy` - I'd probably want that anyway
///
/// ### Safety
/// [`Moveable::mv`] function MUST respect following specification:
/// - at function call, `dst` points to properly aligned, but initialized memory
/// - at function call, `src` points to a live, valid version of the type
/// - after function call, `dst` must contain live, valid version of the type
pub unsafe trait Moveable {
    /// Moves value from `src` to `dst`
    ///
    /// ### Safety
    /// - both pointers must be aligned
    /// - both pointers must be valid for reads and writes
    /// - `src` must point to live, valid version of the type
    unsafe fn mv(dst: *mut Self, src: *mut Self);
}

// SAFETY: Copy types have trivial move semantics
unsafe impl<T: Copy> Moveable for T {
    unsafe fn mv(dst: *mut Self, src: *mut Self) {
        // SAFETY:
        // - src is valid for reads of T
        // - dst is valid for writes of T
        // - by definition, Copy types can be copied around as a bunch of bytes
        unsafe { core::ptr::copy(src, dst, 1) };
    }
}

/// Represents container that can be used to safely handle types with non-trivial move semantics
///
/// ### Examples
/// Container types usually end in "Container": [`BoxContainer`], [`ArcContainer`], [`RefContainer`], etc. You may implement your own, and most methods would accept it just fine.
///
/// Typically, container lifecycle involves:
///
/// 1. Creation of uninit container:
/// ```rust
/// # use sdecay::container::Container;
/// struct S(i32);
///
/// fn use_container<C: Container<Inner = S>>(allocator: C::Allocator) {
///     let mut uninit = C::uninit(allocator);
///     // (...)
/// }
/// ```
/// 2. Container initialization:
/// ```rust
/// # use sdecay::container::Container;
/// # struct S(i32);
/// # fn use_container<C: Container<Inner = S>>(allocator: C::Allocator) {
/// #    let mut uninit = C::uninit(allocator);
///     // get pointer
///     let ptr = C::uninit_inner_ptr(&mut uninit);
///     // initialize (for example, call a C++ constructor)
///     unsafe { core::ptr::write(ptr, S(42)) };
///     let container = unsafe { C::init(uninit) };
/// # }
/// ```
/// Alternatively, with single unsafe block:
/// ```rust
/// # use sdecay::container::Container;
/// # struct S(i32);
/// # fn use_container<C: Container<Inner = S>>(allocator: C::Allocator) {
///     let container = unsafe {
///         C::init_ptr(allocator, |ptr| unsafe { core::ptr::write(ptr, S(42)) })
///     };
/// # }
/// ```
/// 3. Container use:
/// ```rust
///# struct S(i32);
/// impl S {
///     fn use_ref(&self) { /* use behind shared reference */ }
///     fn use_mut(self: Pin<&mut Self>) { /* use behind exclusive reference */ }
/// }
/// // fn
/// # use core::pin::Pin;
/// # use sdecay::container::Container;
/// # fn use_container<C: Container<Inner = S>>(allocator: C::Allocator) {
/// #    let mut uninit = C::uninit(allocator);
/// #    // get pointer
/// #    let ptr = C::uninit_inner_ptr(&mut uninit);
/// #    // initialize (for example, call a C++ constructor)
/// #    unsafe { core::ptr::write(ptr, S(42)) };
/// #    let mut container = unsafe { C::init(uninit) };
///     container.use_ref(); // &T can be used right away, since `Container` requires `Deref`
///
///     // while getting exclusive reference, Option is returned, None indicating non-exclusive access to data
///     container.try_inner().unwrap().use_mut();
///     // note function signature - exclusive reference is always pinned
/// # }
/// ```
/// If you would want your container to always have unique access to data, use [`ExclusiveContainer`]:
/// ```rust
/// # use core::pin::Pin;
/// # use sdecay::container::ExclusiveContainer;
/// # struct S(i32);
/// # impl S {
/// #    fn use_ref(&self) { /* use behind shared reference */ }
/// #
/// #    fn use_mut(self: Pin<&mut Self>) { /* use behind exclusive reference */ }
/// # }
///fn use_container<C: ExclusiveContainer<Inner = S>>(allocator: C::Allocator) {
/// #    let mut uninit = C::uninit(allocator);
/// #    // get pointer
/// #    let ptr = C::uninit_inner_ptr(&mut uninit);
/// #    // initialize (for example, call a C++ constructor)
/// #    unsafe { core::ptr::write(ptr, S(42)) };
/// #    let mut container = unsafe { C::init(uninit) };
///     // (usual initialization)
///     container.inner().use_mut(); // no unwrap required, no panic possible
/// }
/// ```
/// 4. Drop or move out:
/// - drop
/// ```rust
/// # use sdecay::container::Container;
/// # struct S(i32);
/// # fn use_container<C: Container<Inner = S>>(allocator: C::Allocator) {
/// #    let mut uninit = C::uninit(allocator);
/// #    // get pointer
/// #    let ptr = C::uninit_inner_ptr(&mut uninit);
/// #    // initialize (for example, call a C++ constructor)
/// #    unsafe { core::ptr::write(ptr, S(42)) };
/// #    let mut container = unsafe { C::init(uninit) };
///     core::mem::drop(container); // (containers are intended to have drop impl)
/// # }
/// ```
/// - move out
/// ```rust
/// # use sdecay::container::Container;
/// # #[derive(Clone, Copy)]
/// # struct S(i32);
/// # fn use_container<C: Container<Inner = S> + core::fmt::Debug>(allocator: C::Allocator) {
/// #   let mut uninit = C::uninit(allocator);
/// #   // get pointer
/// #   let ptr = C::uninit_inner_ptr(&mut uninit);
/// #   // initialize (for example, call a C++ constructor)
/// #   unsafe { core::ptr::write(ptr, S(42)) };
/// #   let mut container = unsafe { C::init(uninit) };
///     let i42 = container.try_move_out(|ptr| unsafe { ptr.read() }).unwrap();
/// #   assert_eq!(i42.0, 42);
/// # }
/// ```
/// - move to different container
/// ```rust
/// # use core::mem::MaybeUninit;
/// # use sdecay::container::{Container, ExclusiveContainer, RefContainer};
/// # #[derive(Clone, Copy)]
/// # struct S(i32);
/// # fn use_container<C: Container<Inner = S> + core::fmt::Debug>(allocator: C::Allocator) {
/// #    let mut uninit = C::uninit(allocator);
/// #    // get pointer
/// #    let ptr = C::uninit_inner_ptr(&mut uninit);
/// #    // initialize (for example, call a C++ constructor)
/// #    unsafe { core::ptr::write(ptr, S(42)) };
/// #    let mut container = unsafe { C::init(uninit) };
///     // while moving, `Result<NewContainer, OldContainer>` is returned, Err indicating non-exclusive access
///     let mut tmp = MaybeUninit::uninit();
///     let new_container = container.try_mv::<RefContainer<'_, _>>(&mut tmp).unwrap();
/// #    let i42 = new_container.move_out(|ptr| unsafe { ptr.read() });
/// #    assert_eq!(i42.0, 42);
/// # }
/// ```
/// Alternatively, use [`ExclusiveContainer`]:
/// ```rust
/// # use core::mem::MaybeUninit;
/// # use sdecay::container::{Container, ExclusiveContainer, RefContainer};
/// # #[derive(Clone, Copy)]
/// # struct S(i32);
/// fn use_container<C: ExclusiveContainer<Inner = S>>(allocator: C::Allocator) {
/// #   let mut uninit = C::uninit(allocator);
/// #   // get pointer
/// #   let ptr = C::uninit_inner_ptr(&mut uninit);
/// #   // initialize (for example, call a C++ constructor)
/// #   unsafe { core::ptr::write(ptr, S(42)) };
/// #   let mut container = unsafe { C::init(uninit) };
///     // (usual initialization)
///     let mut tmp = MaybeUninit::uninit();
///     let new_container = container.mv::<RefContainer<'_, _>>(&mut tmp); // NOTE: no unwrap
/// #   let i42 = new_container.move_out(|ptr| unsafe { ptr.read() });
/// #   assert_eq!(i42.0, 42);
/// }
/// ```
/// ### Safety
/// - [`Container::Uninit`] *must not* allow any form of shared ownership. If the container itself or inner type do implement shared ownership, they must be sufficiently encapsulated to not allow it until [`Container::init`] call
/// - Moving this type should NOT move referenced [`Container::Inner`]
/// - Dropping this type is expected to drop [`Container::Inner`] (i.e. all resources should be freed appropriately by just dropping the container, no extra calls required)
pub unsafe trait Container:
    Deref<Target = Self::Inner> + AsRef<Self::Inner> + Sized
{
    /// Type used to create uninitialized version of the container
    ///
    /// Usually this is a `()`; at the moment, [`RefContainer`] is the only container having a different type -- `&mut [MaybeUninit]`
    type Allocator;
    /// Contained type
    type Inner;
    /// Container in the uninitialized state. Usually somewhat similar to container itself
    ///
    /// Notably, these types should not be
    type Uninit;

    /// Creates container in the uninitialized state
    ///
    /// ### Example
    /// Note, that argument type is defined by the container. Here are some examples:
    ///
    /// - box container:
    /// ```rust
    /// # #[cfg(feature = "alloc")] {
    /// # use sdecay::container::{BoxContainer, Container};
    /// BoxContainer::<i32>::uninit(());
    /// # }
    /// ```
    /// - ref container:
    /// ```rust
    /// # use core::mem::MaybeUninit;
    /// # use sdecay::container::{RefContainer, Container};
    /// let mut tmp = MaybeUninit::uninit();
    /// RefContainer::<'_, i32>::uninit(&mut tmp);
    /// ```
    fn uninit(allocator: Self::Allocator) -> Self::Uninit;

    /// Retrieves pointer to the contents of uninit container
    fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner;

    /// ### Safety
    /// Memory managed by the pointer must contain a valid [`Container::Inner`]. To initialize the value, use pointer returned by [`Container::uninit_inner_ptr`]
    unsafe fn init(uninit: Self::Uninit) -> Self;

    /// Gets exclusive reference to inner value. Note that exclusive reference is always pinned
    ///
    /// ### Returns
    /// [`Option::None`] variant indicates non-exclusive memory access, for example, function was called on [`ArcContainer`] having other [`ArcContainer`] (s) pointing to the same value
    fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>>;

    /// Moves value out of the container. `action` is called *at most once* (i.e. 1 or 0 times) and provided with a pointer to *contained* value (i.e. it is valid for reads and points to valid [`Container::Inner`])
    ///
    /// ### UB warning
    /// *NOTE*: you may try doing this manually, like this:
    /// ```rust,ignore
    /// let container: impl Container<Inner = T> = /* */;
    /// let ptr: *const T = core::ptr::from_ref(&*container).cast_mut();
    /// // move value out of `ptr`
    /// ```
    ///
    /// This implementation is flawed, since [`Container`] will drop contained value again at it's drop point
    ///
    /// However, even adding
    /// ```rust,ignore
    /// core::mem::forget(container);
    /// ```
    /// Will still most likely be a UB, since it assumes valid container as argument of [`core::mem::forget`], which would likely imply valid `T` still contained inside
    ///
    /// This by itself IS safe, since it's call can only ever **leak** the resources, for example, like this:
    /// ```rust,ignore
    /// let container: impl Container<Inner = T> = /* */;
    /// container.try_move_out(|ptr: *mut T| {
    ///     // w-what is this scary `*mut T`-thing?
    ///     // I'm scared of it, I guess let's just ignore it
    ///     let _ = ptr;
    /// }).expect("Should have exclusive memory access to leak resources");
    /// // resources managed by `T` were leaked at this point
    /// ```
    ///
    /// Considering examples above, please take care, while implementing this function.
    fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O>;

    /// Provided helper function creating and initializing the container in a single call
    ///
    /// ### Example
    ///
    /// ```rust
    /// # #[cfg(feature = "alloc")] {
    /// # use sdecay::container::{BoxContainer, Container};
    /// let container = unsafe { BoxContainer::init_ptr((), |ptr: *mut i32| unsafe { core::ptr::write(ptr, 42) }) };
    /// # }
    /// ```
    ///
    /// ### Safety
    ///
    /// `initializer` must *actually initialize* the value behind a pointer. It is a UB to not do that:
    /// ```rust,no_run
    /// # #[cfg(feature = "alloc")] {
    /// # use sdecay::container::{Container, BoxContainer};
    /// # type T = Box<()>;
    /// let container = unsafe { BoxContainer::<T>::init_ptr((), |_ptr: *mut T| {}) };
    /// // `container` assumes T is init, while it is not, technically this is a UB
    /// # }
    /// ```
    #[inline]
    unsafe fn init_ptr(
        allocator: Self::Allocator,
        initializer: impl FnOnce(*mut Self::Inner),
    ) -> Self {
        let mut uninit = Self::uninit(allocator);
        let ptr = Self::uninit_inner_ptr(&mut uninit);
        initializer(ptr);
        // SAFETY: `initializer` should have initialized contained data. It is a UB to not do so, that is why this function is `unsafe`
        unsafe { Self::init(uninit) }
    }

    /// Tries moving value out of the container into a different container
    ///
    /// ### Returns
    /// - `None` indicates fail to move due to non-exclusive access
    ///
    /// ### Bound
    /// This method has a "[`Container::Inner`]: [`Moveable`]" bound to respect possible move constructors.
    ///
    /// ### Example
    /// Moving from [`BoxContainer`] into [`ArcContainer`]:
    ///
    /// ```rust
    /// # #[cfg(feature = "alloc")] {
    /// # use sdecay::container::{BoxContainer, ArcContainer, Container};
    /// let box_container = unsafe { BoxContainer::init_ptr((), |ptr| unsafe { core::ptr::write(ptr, 42) }) };
    /// let arc_container = box_container.try_mv::<ArcContainer<_>>(()).expect("Should always be able to move from Box");
    /// # }
    /// ```
    ///
    /// In fact, when moving from box (or any other exclusive container), `expect`ing can be avoided by using [`ExclusiveContainer::mv`]:
    /// ```rust
    /// # #[cfg(feature = "alloc")] {
    /// # use sdecay::container::{Container, ExclusiveContainer, BoxContainer, ArcContainer};
    /// # let box_container = unsafe { BoxContainer::init_ptr((), |ptr| unsafe { core::ptr::write(ptr, 42) }) };
    /// let arc_container = box_container.mv::<ArcContainer<_>>(());
    /// # }
    /// ```
    ///
    /// Note that reversed operation can fail:
    /// ```rust
    /// # #[cfg(feature = "alloc")] {
    /// # use sdecay::container::{Container, BoxContainer, ArcContainer};
    /// let arc_container = unsafe { ArcContainer::init_ptr((), |ptr| unsafe { core::ptr::write(ptr, 42) }) };
    /// let box_container = arc_container.try_mv::<BoxContainer<_>>(()).expect("Should move from exclusive arc container");
    /// // but,
    /// let arc_container = unsafe { ArcContainer::init_ptr((), |ptr| unsafe { core::ptr::write(ptr, 42) }) };
    /// let arc_container2 = arc_container.clone();
    /// assert!(arc_container.try_mv::<BoxContainer<_>>(()).is_none());
    /// # core::mem::drop(arc_container2);
    /// # }
    /// ```
    #[inline]
    fn try_mv<C: Container<Inner = Self::Inner>>(self, allocator: C::Allocator) -> Option<C>
    where
        Self::Inner: Moveable,
    {
        self.try_move_out(|src| {
            // NOTE: `src` is valid for reads and points to a valid instance of `T`
            let mv = move |dst: *mut Self::Inner| {
                // NOTE: assuming `dst` is valid for writes sized as `T`
                // SAFETY: (see notes above)
                // - `src` is valid for reads
                // - `src` points to valid T
                // - `dst` is valid writes
                unsafe { C::Inner::mv(dst, src) }
            };
            // SAFETY: `mv` does initialize the value by calling `Moveable::mv`
            unsafe { C::init_ptr(allocator, mv) }
        })
    }

    /// Provided helper function initializing the [`Container`] by moving a value into it
    ///
    /// To be honest, this kinda defeat the purpose, so it's here just for easier initialization in examples, I guess
    #[inline]
    fn init_value(allocator: Self::Allocator, value: Self::Inner) -> Self {
        let w = |dst| {
            // SAFETY:
            // - `dst` is valid for writes of `T`
            unsafe {
                core::ptr::write(dst, value);
            }
        };
        // SAFETY: `w` writes a valid value into `dst`, initializing it
        unsafe { Self::init_ptr(allocator, w) }
    }
}

/// Extension of [`Container`] trait implemented for containers always having a unique data access
///
/// Note that this trait is safe, as it does not impose any implicit contract over [`Container`]
pub trait ExclusiveContainer: Container {
    /// Gets exclusive reference to inner value. Note that exclusive reference is always pinned
    fn inner(&mut self) -> Pin<&mut Self::Inner>;

    /// Moves value out of the container. `action` is called *exactly once*, and provided with a pointer to *contained* value
    ///
    /// ### UB warning
    /// See [`Container::try_move_out`] doc
    ///
    /// Please take care, while implementing this function.
    fn move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> O;

    /// Moves value out of the container into a different container
    ///
    /// ### Bound
    /// This method has a "[`Container::Inner`]: [`Moveable`]" bound to respect possible move constructors.
    ///
    /// ### Example
    /// Moving from [`BoxContainer`] into [`ArcContainer`]:
    ///
    /// ```rust
    /// # #[cfg(feature = "alloc")] {
    /// # use core::pin::Pin;
    /// # use sdecay::container::{ArcContainer, BoxContainer, Container, ExclusiveContainer};
    /// let box_container = unsafe { BoxContainer::init_ptr((), |ptr| unsafe { core::ptr::write(ptr, 42) }) };
    /// let arc_container = box_container.mv::<ArcContainer<_>>(());
    /// # }
    /// ```
    ///
    /// Note that reverse operation is not implemented, since [`ArcContainer`] is not an [`ExclusiveContainer`]:
    /// ```rust,compile_fail
    /// # #[cfg(feature = "alloc")] {
    /// # use core::pin::Pin;
    /// # use sdecay::container::{ArcContainer, BoxContainer, Container, ExclusiveContainer};
    /// let arc_container = unsafe { ArcContainer::init_ptr((), |ptr| unsafe { core::ptr::write(ptr, 42) }) };
    /// let box_container = arc_container.mv::<BoxContainer<_>>(());
    /// # }
    /// # #[cfg(not(feature = "alloc"))] {
    /// # compile_fail!("Dummy compile fail, if no `alloc`");
    /// # }
    /// ```
    fn mv<C: Container<Inner = Self::Inner>>(self, allocator: C::Allocator) -> C
    where
        Self::Inner: Moveable,
    {
        self.move_out(|src| {
            // NOTE: `src` is valid for reads and points to a valid instance of `T`
            let mv = move |dst: *mut Self::Inner| {
                // NOTE: assuming `dst` is valid for writes sized as `T`
                // SAFETY: (see notes above)
                // - `src` is valid for reads
                // - `src` points to valid T
                // - `dst` is valid writes
                unsafe { C::Inner::mv(dst, src) }
            };
            // SAFETY: `mv` does initialize the value by calling `Moveable::mv`
            unsafe { C::init_ptr(allocator, mv) }
        })
    }
}

macro_rules! impl_container_traits {
    ($c:ty $(| <$($args:tt),+> $(lt: <$($l:lifetime),+>)?)?) => {
        impl $(<$($args),+>)? AsRef<<$c as Container>::Inner> for $c {
            #[inline]
            fn as_ref(&self) -> &<$c as Container>::Inner {
                &*self
            }
        }

        impl $(<$($args),+>)? $c {
            #[doc = concat!("Same as `<&Self as IntoIterator>::into_iter(self)`")]
            #[inline]
            pub fn iter<'r0>(&'r0 self) -> <&'r0 Self as IntoIterator>::IntoIter
            where
                $($($($l : 'r0,)+)?)?
                for<'r1> &'r1 T: IntoIterator,
            {
                self.into_iter()
            }
        }

        impl <'r0 $(,$($args),+)?> IntoIterator for & 'r0 $c
        where
            $($($($l : 'r0,)+)?)?
            for<'r1> &'r1 T: IntoIterator,
        {
            type Item = <&'r0 T as IntoIterator>::Item;

            type IntoIter = <&'r0 T as IntoIterator>::IntoIter;

            fn into_iter(self) -> Self::IntoIter {
                <&'r0 T as IntoIterator>::into_iter(&*self)
            }
        }
    };
}

#[derive(Debug)]
#[doc(hidden)]
#[cfg(feature = "alloc")]
pub struct UninitBoxContainer<T>(Box<MaybeUninit<T>>);

/// [`Container`] implementation via [`Box`]
///
/// Implements [`ExclusiveContainer`]
///
/// ### Example
/// ```rust
/// # use core::pin::Pin;
/// # use sdecay::container::{BoxContainer, Container, ExclusiveContainer};
/// let mut container = BoxContainer::init_value((), 42);
/// let shared: &i32 = &container;
/// let exclusive: Pin<&mut i32> = container.inner();
/// let container2 = container.mv::<BoxContainer<_>>(());
/// ```
#[derive(Debug)]
#[cfg(feature = "alloc")]
pub struct BoxContainer<T>(Pin<Box<T>>);

#[cfg(feature = "alloc")]
impl<T> Deref for BoxContainer<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[cfg(feature = "alloc")]
impl<T: core::fmt::Display> core::fmt::Display for BoxContainer<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        T::fmt(&self.0, f)
    }
}

#[cfg(feature = "alloc")]
// SAFETY:
// - `UninitBoxContainer` does not introduce shared ownership
// - Moving `BoxContainer` does not move `T`
// - Dropping `BoxContainer` drops the `T`
unsafe impl<T> Container for BoxContainer<T> {
    type Allocator = ();
    type Inner = T;
    type Uninit = UninitBoxContainer<T>;

    #[inline]
    fn uninit(_allocator: ()) -> Self::Uninit {
        UninitBoxContainer(Box::new_uninit())
    }

    #[inline]
    fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner {
        uninit.0.as_mut_ptr()
    }

    #[inline]
    unsafe fn init(uninit: Self::Uninit) -> Self {
        // SAFETY: value contained in the box must be init (function requirement)
        let init_ptr = unsafe { uninit.0.assume_init() };
        // SAFETY:
        // - exclusive reference is only ever exposed as `Pin<&mut T>`
        // - memory is unpinned only after drop call, or `Container::move_out` (`core::mem::forget` at most)
        let pin = unsafe { Pin::new_unchecked(init_ptr) };
        Self(pin)
    }

    #[inline]
    fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>> {
        Some(self.inner())
    }

    #[inline]
    fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O> {
        Some(self.move_out(action))
    }
}

#[cfg(feature = "alloc")]
impl<T> ExclusiveContainer for BoxContainer<T> {
    #[inline]
    fn inner(&mut self) -> Pin<&mut Self::Inner> {
        self.0.as_mut()
    }

    #[inline]
    fn move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> O {
        // SAFETY: none of the operations below will expose `&mut T` to the caller, or move the data directly. Any possible movement logic is handled by the `action` closure, and it's up to it to call any sort of destructor and such
        //
        // After this call, contained `T` is assumed to be dropped or moved in a way respecting all `T`s invariants. Regardless, data is not read or assumed to be a valid `T` again
        let bx = unsafe { Pin::into_inner_unchecked(self.0) };
        let ptr = Box::into_raw(bx);
        let res = action(ptr);
        let uptr = ptr.cast::<MaybeUninit<T>>(); // `ptr`'s pointee was invalidated by `action`
        // SAFETY:
        // - `uptr` is derived from `ptr`, obtained from call to `Box::into_raw`
        // - `MaybeUninit<T>` has the same layout as `T`
        let ubx = unsafe { Box::from_raw(uptr) };
        // free the box allocation
        core::mem::drop(ubx);
        res
    }
}

#[cfg(feature = "alloc")]
impl_container_traits!(BoxContainer<T> | <T>);

// This is a helper function specifically designed to help calling `Ptr`'s functions. Care should be taken to uphold pin invariants while doing so
#[cfg(feature = "alloc")]
unsafe fn pin_inner_mut<Ptr>(pin: &mut Pin<Ptr>) -> &mut Ptr {
    let ptr = core::ptr::from_mut(pin).cast();
    // SAFETY:
    // - ptr validity: `Pin<Ptr>` has the same layout as `Ptr`
    // - pin invariant: see function doc
    unsafe { &mut *ptr }
}

#[cfg(feature = "alloc")]
mod simple_arc;
#[cfg(feature = "alloc")]
use simple_arc::Arc;

#[doc(hidden)]
#[cfg(feature = "alloc")]
pub struct UninitArcContainer<T>(Arc<MaybeUninit<T>>);

#[cfg(feature = "alloc")]
impl<T> core::fmt::Debug for UninitArcContainer<T> {
    #[inline]
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_tuple("UninitArcContainer").field(&*self.0).finish()
    }
}

/// [`Container`] implementation via privately implemented `Arc`
///
/// ### Example
/// ```rust
/// # use core::pin::Pin;
/// # use sdecay::container::{Container, ArcContainer};
/// let mut container = ArcContainer::init_value((), 42);
///
/// let shared: &i32 = &container;
/// let exclusive: Pin<&mut i32> = container.try_inner().expect("Single Arc should have exclusive access");
/// let mut container2 = container.try_mv::<ArcContainer<_>>(()).expect("Single Arc should be always successfully moved out of");
///
/// let container3 = container2.clone(); // container is not longer exclusive
///
/// assert!(container2.try_inner().is_none(), "Non-excluive Arc should not be able to get &mut");
/// let shared: &i32 = &container2; // shared reference is still ok
/// assert!(container2.try_mv::<ArcContainer<_>>(()).is_none());
/// ```
#[derive(Debug)]
#[cfg(feature = "alloc")]
pub struct ArcContainer<T>(Pin<Arc<T>>);

#[cfg(feature = "alloc")]
impl<T> Clone for ArcContainer<T> {
    #[inline]
    fn clone(&self) -> Self {
        Self(self.0.clone())
    }
}

#[cfg(feature = "alloc")]
impl<T> Deref for ArcContainer<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[cfg(feature = "alloc")]
impl<T: core::fmt::Display> core::fmt::Display for ArcContainer<T> {
    #[inline]
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        T::fmt(&self.0, f)
    }
}

#[cfg(feature = "alloc")]
// SAFETY:
// - `UninitArcContainer` does not introduce shared ownership (it does contain `Arc`, but it's SO capability is encapsulated)
// - Moving `ArcContainer` does not move `T`
// - Dropping all `ArcContainer`s referring to the same `T`, drops the `T`
unsafe impl<T> Container for ArcContainer<T> {
    type Allocator = ();
    type Inner = T;
    type Uninit = UninitArcContainer<T>;

    #[inline]
    fn uninit(_allocator: ()) -> Self::Uninit {
        UninitArcContainer(Arc::uninit())
    }

    #[inline]
    fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner {
        // SAFETY: `Self::Uninit` cannot be cloned and thus guaranteed unique access
        let rf = unsafe { uninit.0.get_mut_unchecked() };
        rf.as_mut_ptr()
    }

    #[inline]
    unsafe fn init(uninit: Self::Uninit) -> Self {
        // SAFETY: value contained in the arc must be init (function invariant)
        let init_ptr: Arc<_> = unsafe { uninit.0.assume_init() };
        // SAFETY:
        // - exclusive reference is only ever exposed as `Pin<&mut T>`
        // - memory is unpinned only after drop call, or `Container::move_out` (`core::mem::forget` at least)
        let pin = unsafe { Pin::new_unchecked(init_ptr) };
        Self(pin)
    }

    #[inline]
    fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>> {
        // SAFETY:
        // - I'll only use `&mut Arc` to call `Arc::get_mut` here
        // - `Arc::get_mut` is not interacting with `T` at all (apart from creating reference to it)
        // - obtained reference is pinned again shortly below, and only returned as pinned
        let arc = unsafe { pin_inner_mut(&mut self.0) };
        if let Some(refm) = Arc::get_mut(arc) {
            // SAFETY: `&mut T` refers to already-pinned `T`, that was unpinned right above to use `Arc::get_mut`
            Some(unsafe { Pin::new_unchecked(refm) })
        } else {
            None
        }
    }

    #[inline]
    fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O> {
        // SAFETY:
        // - `Arc::try_move_out` does not move the internal value
        // - if `action` is ever called, value is not assumed to be init after that
        let arc = unsafe { Pin::into_inner_unchecked(self.0) };
        arc.try_move_out(action)
    }
}

#[cfg(feature = "alloc")]
impl_container_traits!(ArcContainer<T> | <T>);

#[derive(Debug)]
#[doc(hidden)]
pub struct UninitRefContainer<'r, T>(&'r mut MaybeUninit<T>);

/// [`Container`] implementation via exclusive reference to [`MaybeUninit`]
///
/// Implements [`ExclusiveContainer`]
///
/// ### Example
/// ```rust
/// # use core::{mem::MaybeUninit, pin::Pin};
/// # use sdecay::container::{RefContainer, Container, ExclusiveContainer};
/// let mut tmp = MaybeUninit::uninit();
/// let mut container = RefContainer::init_value(&mut tmp, 42);
/// let shared: &i32 = &container;
/// let exclusive: Pin<&mut i32> = container.inner();
/// let mut tmp = MaybeUninit::uninit();
/// let container2 = container.mv::<RefContainer<_>>(&mut tmp);
/// ```
/// Note that this container has a non-`()` allocator, and you might want to explicitly allocate `MaybeUninit`:
/// ```rust
/// # use core::mem::MaybeUninit;
/// # use sdecay::container::{RefContainer, Container};
/// let mut tmp = MaybeUninit::uninit();
/// let container = RefContainer::init_value(&mut tmp, 42);
/// ```
/// This works just fine too, although a bit verbose
#[derive(Debug)]
pub struct RefContainer<'r, T>(Option<Pin<&'r mut T>>);

impl<T> Deref for RefContainer<'_, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.0.as_ref().unwrap()
    }
}

impl<T> Drop for RefContainer<'_, T> {
    #[inline]
    fn drop(&mut self) {
        // I'd like to move out of option (no good reason for that, really)
        let Some(pin): Option<Pin<&mut T>> = self.0.take() else {
            // pin was taken away by `Container::move_out` method. Nothing to do: data was dropped already
            return;
        };
        // now I need to manually drop the value behind the exclusive reference
        //
        // although exclusive reference provides an exclusive access to data, it can't be alive at all, after data is invalidated - we need to use raw `*mut T` and `core::mem::drop_in_place` call
        // SAFETY: data will not be moved out, and will be dropped in a couple lines
        let rf = unsafe { Pin::into_inner_unchecked(pin) };
        // pin no longer exists
        let ptr = core::ptr::from_mut(rf);
        // reference no longer exists
        // SAFETY:
        // - `ptr` points to valid `T`, as it was derived from a `&mut T`
        // - at this point, data is only referred to as `*mut T` (and possibly as `&mut MaybeUninit<T>` from the outer scope)
        unsafe { core::ptr::drop_in_place(ptr) };
    }
}

impl<T: core::fmt::Display> core::fmt::Display for RefContainer<'_, T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        T::fmt(self.0.as_ref().unwrap(), f)
    }
}

// SAFETY:
// - `UninitRefContainer` does not introduce shared ownership
// - Moving `RefContainer` does not move `T`
// - Dropping `RefContainer` drops the `T`
unsafe impl<'r, T> Container for RefContainer<'r, T> {
    type Allocator = &'r mut MaybeUninit<T>;
    type Inner = T;
    type Uninit = UninitRefContainer<'r, T>;

    #[inline]
    fn uninit(allocator: Self::Allocator) -> Self::Uninit {
        UninitRefContainer(allocator)
    }

    #[inline]
    fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner {
        uninit.0.as_mut_ptr()
    }

    #[inline]
    unsafe fn init(uninit: Self::Uninit) -> Self {
        // SAFETY: value pointed by the `&mut MaybeUninit` must be init (function invariant)
        let ref_mut = unsafe { uninit.0.assume_init_mut() };
        // SAFETY:
        // - exclusive reference is only ever exposed as `Pin<&mut T>`
        // - memory is unpinned only after drop call, or `Container::move_out` (`core::mem::forget` at most)
        let pin = unsafe { Pin::new_unchecked(ref_mut) };
        Self(Some(pin))
    }

    #[inline]
    fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>> {
        Some(self.inner())
    }

    #[inline]
    fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O> {
        Some(self.move_out(action))
    }
}

impl<T> ExclusiveContainer for RefContainer<'_, T> {
    #[inline]
    fn inner(&mut self) -> Pin<&mut Self::Inner> {
        self.0.as_mut().unwrap().as_mut()
    }

    #[inline]
    fn move_out<O>(mut self, action: impl FnOnce(*mut Self::Inner) -> O) -> O {
        // SAFETY: none of the operations below will expose `&mut T` to the caller, or move the data directly. Any possible movement logic is handled by the `action` closure, and it's up to it to call any sort of destructor and such
        //
        // After this call, contained `T` is assumed to be dropped or moved in a way respecting all `T`s invariants. Regardless, data is not read or assumed to be a valid `T` again
        let pin = self
            .0
            .take()
            .expect("Should contain the pin, since it's only ever taken out by this function and a destructor (both can only be called once)");
        // SAFETY: extracted `&mut T` will only be passed to `action`, which is assumed to call value's destructor
        let rf = unsafe { Pin::into_inner_unchecked(pin) };
        // pin no longer exists
        let ptr = core::ptr::from_mut(rf);
        // `&mut T` no longer exists
        action(ptr) // value is dropped, result returned
    }
}

impl_container_traits!(RefContainer<'r, T> | <'r, T> lt: <'r>);

#[cfg(test)]
mod tests;