dst_init/
lib.rs

1//! A library for rust to provide ways to emplace dynamic sized type
2//! ```rust
3//! #![feature(alloc_layout_extra)]
4//! #![feature(ptr_metadata)]
5//!
6//! use dst_init_macros::dst;
7//! use dst_init::{BoxExt, Slice, SliceExt};
8//! #[dst]
9//! #[derive(Debug)]
10//! struct Test<A, B, C, D> {
11//!     a: A,
12//!     b: B,
13//!     c: C,
14//!     dst: [(C, D)],
15//! }
16//!
17//! #[dst]
18//! #[derive(Debug)]
19//! struct Test1<A, B, C, D> {
20//!     a: usize,
21//!     t: Test<A, B, C, D>,
22//! }
23//!
24//! let t = TestInit {
25//!     a: 1usize,
26//!     b: 1u8,
27//!     c: 1u8,
28//!     dst: Slice::iter_init(3, (0..).map(|i| (i as u8, i as usize))),
29//! };
30//! let u = Test1Init { a: 1usize, t };
31//! let a = Box::emplace(u);
32//! assert_eq!(a.a,1usize);
33//! assert_eq!(a.t.a,1);
34//! assert_eq!(a.t.b,1);
35//! assert_eq!(a.t.c,1);
36//! assert_eq!(a.t.dst,[(0,0),(1,1),(2,2)]);
37//!
38//! ```
39#![feature(ptr_metadata)]
40#![feature(unsize)]
41#![feature(alloc_layout_extra)]
42#![feature(allocator_api)]
43
44pub mod alloc;
45
46pub use dst_init_macros as macros;
47pub use macros::dst;
48use std::alloc::Layout;
49use std::marker::{PhantomData, Unsize};
50use std::ptr::{null, NonNull, Pointee};
51use std::{mem, ptr};
52use std::rc::Rc;
53use std::sync::Arc;
54
55type Metadata<T> = <T as Pointee>::Metadata;
56
57#[inline(always)]
58const fn metadata_of<T: Unsize<Dyn>, Dyn: ?Sized>() -> Metadata<Dyn> {
59    let null: *const T = null();
60    let dyn_null = null as *const Dyn;
61    ptr::metadata(dyn_null)
62}
63
64pub trait Initializer<DstInit: EmplaceInitializer> {
65    type Init;
66}
67
68pub type Init<T, DstInit> = <T as Initializer<DstInit>>::Init;
69
70/// An abstract interface for all emplace initializer
71pub trait EmplaceInitializer {
72    type Output: ?Sized;
73    /// Layout of the type
74    fn layout(&mut self) -> Layout;
75    /// Emplace the type in given memory
76    fn emplace(self, ptr: NonNull<u8>) -> NonNull<Self::Output>;
77}
78
79/// An Emplace Initializer for Slice, created by iterator and member number.
80pub struct SliceIterInitializer<Iter: Iterator> {
81    size: usize,
82    iter: Iter,
83}
84
85impl<Iter: Iterator> SliceIterInitializer<Iter> {
86    /// Create a SliceIterInitializer by iterator and member number. iterator::next will be called
87    /// for given member number times
88    ///
89    /// # Panics
90    /// would panic if iterator has less item than given member number
91    #[inline(always)]
92    pub fn new(size: usize, iter: Iter) -> Self {
93        Self { size, iter }
94    }
95}
96
97impl<Iter: Iterator> EmplaceInitializer for SliceIterInitializer<Iter> {
98    type Output = [Iter::Item];
99
100    #[inline(always)]
101    fn layout(&mut self) -> Layout {
102        Layout::array::<Iter::Item>(self.size).unwrap()
103    }
104
105    #[inline(always)]
106    fn emplace(mut self, ptr: NonNull<u8>) -> NonNull<Self::Output> {
107        unsafe {
108            let mut p: *mut Iter::Item = ptr.as_ptr().cast();
109            for _ in 0..self.size {
110                let item = self.iter.next().unwrap();
111                p.write(item);
112                p = p.add(1);
113            }
114            mem::transmute(NonNull::slice_from_raw_parts(
115                ptr.cast::<Iter::Item>(),
116                self.size,
117            ))
118        }
119    }
120}
121
122/// An Emplace Initializer for Slice, created by closure and member number.
123pub struct SliceFnInitializer<Item, F: FnMut() -> Item> {
124    size: usize,
125    f: F,
126}
127
128impl<Item, F: FnMut() -> Item> SliceFnInitializer<Item, F> {
129    /// Create a SliceIterInitializer by closure and member number. Given closure will be called
130    /// for given member number times
131    #[inline(always)]
132    pub fn new(size: usize, f: F) -> Self {
133        Self { size, f }
134    }
135}
136
137impl<Item, F: FnMut() -> Item> EmplaceInitializer for SliceFnInitializer<Item, F> {
138    type Output = [Item];
139
140    #[inline(always)]
141    fn layout(&mut self) -> Layout {
142        Layout::array::<Item>(self.size).unwrap()
143    }
144
145    #[inline(always)]
146    fn emplace(mut self, ptr: NonNull<u8>) -> NonNull<Self::Output> {
147        unsafe {
148            let mut p: *mut Item = ptr.as_ptr().cast();
149            for _ in 0..self.size {
150                let item = (self.f)();
151                p.write(item);
152                p = p.add(1);
153            }
154            NonNull::slice_from_raw_parts(ptr.cast::<Item>(), self.size)
155        }
156    }
157}
158
159/// An Emplace Initializer for `dyn` or `[T]` types, created by concrete type `T` or `[T;N]`.
160/// For example `usize` is sized type and implemented `Debug`:
161///```rust
162/// use std::fmt::Debug;
163/// use dst_init::{BoxExt, CoercionInitializer};
164///
165/// let init:CoercionInitializer<usize,dyn Debug> = CoercionInitializer::new(1usize);
166/// let boxed:Box<dyn Debug> = Box::emplace(init);
167/// assert_eq!(format!("{:?}",boxed),"1")
168///```
169pub struct CoercionInitializer<T: Unsize<U>, U: ?Sized> {
170    t: T,
171    phan: PhantomData<U>,
172}
173
174impl<T: Unsize<U>, U: ?Sized> CoercionInitializer<T, U> {
175    #[inline(always)]
176    pub fn new(t: T) -> Self {
177        Self {
178            t,
179            phan: Default::default(),
180        }
181    }
182    #[inline(always)]
183    pub fn fallback(self) -> T {
184        self.t
185    }
186}
187
188impl<T: Unsize<U>, U: ?Sized> EmplaceInitializer for CoercionInitializer<T, U> {
189    type Output = U;
190
191    #[inline(always)]
192    fn layout(&mut self) -> Layout {
193        Layout::new::<T>()
194    }
195
196    #[inline(always)]
197    fn emplace(self, ptr: NonNull<u8>) -> NonNull<Self::Output> {
198        unsafe {
199            let meta = metadata_of::<T, U>();
200            ptr.as_ptr().cast::<T>().write(self.t);
201            NonNull::from_raw_parts(ptr, meta)
202        }
203    }
204}
205
206/// An Emplace Initializer for sized type, created by itself.
207pub struct DirectInitializer<T> {
208    t: T,
209}
210
211impl<T> DirectInitializer<T> {
212    #[inline(always)]
213    pub fn new(t: T) -> Self {
214        Self { t }
215    }
216
217    #[inline(always)]
218    pub fn fallback(self) -> T {
219        self.t
220    }
221}
222
223impl<T> EmplaceInitializer for DirectInitializer<T> {
224    type Output = T;
225
226    #[inline(always)]
227    fn layout(&mut self) -> Layout {
228        Layout::new::<T>()
229    }
230
231    #[inline(always)]
232    fn emplace(self, ptr: NonNull<u8>) -> NonNull<Self::Output> {
233        unsafe {
234            ptr.as_ptr().cast::<T>().write(self.t);
235            ptr.cast()
236        }
237    }
238}
239
240/// Abstract for type `Box`,`Rc` and etc to allocate value by EmplaceInitializer types.
241pub trait BoxExt: Sized {
242
243    type Output: ?Sized;
244
245    /// Allocate memory by `std::alloc::alloc()` and emplace value in it
246    /// Then use Self wrap it.
247    fn emplace<Init: EmplaceInitializer<Output = Self::Output>>(init: Init) -> Self;
248}
249
250impl<T: ?Sized> BoxExt for Box<T> {
251
252    type Output = T;
253
254    /// Allocate memory by `std::alloc::alloc()` and emplace value in it
255    /// Then use `Box` wrap it.
256    fn emplace<Init: EmplaceInitializer<Output = Self::Output>>(
257        mut init: Init,
258    ) -> Box<Self::Output> {
259        unsafe {
260            let layout = init.layout();
261            let mem = std::alloc::alloc(layout);
262            let obj = init.emplace(NonNull::new(mem).unwrap());
263            Box::from_raw(obj.as_ptr())
264        }
265    }
266}
267
268impl<T: ?Sized> BoxExt for Rc<T> {
269    type Output = T;
270
271    /// Allocate memory by `std::alloc::alloc()` and emplace value in it
272    /// Then use `Rc` wrap it.
273    fn emplace<Init: EmplaceInitializer<Output = Self::Output>>(
274        mut init: Init,
275    ) -> Rc<Self::Output> {
276        unsafe {
277            let layout = init.layout();
278            let mem = std::alloc::alloc(layout);
279            let obj = init.emplace(NonNull::new(mem).unwrap());
280            Rc::from_raw(obj.as_ptr())
281        }
282    }
283}
284
285impl<T: ?Sized> BoxExt for Arc<T> {
286    type Output = T;
287
288    /// Allocate memory by `std::alloc::alloc()` and emplace value in it
289    /// Then use `Arc` wrap it.
290    fn emplace<Init: EmplaceInitializer<Output = Self::Output>>(
291        mut init: Init,
292    ) -> Arc<Self::Output> {
293        unsafe {
294            let layout = init.layout();
295            let mem = std::alloc::alloc(layout);
296            let obj = init.emplace(NonNull::new(mem).unwrap());
297            Arc::from_raw(obj.as_ptr())
298        }
299    }
300}
301
302/// pub type Slice\<T\> = \[T\];
303pub type Slice<T> = [T];
304
305/// Extension for type `[T]` to create EmplaceInitializer.
306pub trait SliceExt {
307    type Item;
308
309    /// create SliceFnInitializer
310    fn fn_init<F>(size: usize, f: F) -> impl EmplaceInitializer<Output = [Self::Item]>
311    where
312        F: FnMut() -> Self::Item;
313
314    /// create SliceIterInitializer
315    fn iter_init<Iter>(size: usize, iter: Iter) -> impl EmplaceInitializer<Output = [Self::Item]>
316    where
317        Iter: Iterator<Item = Self::Item>;
318}
319
320impl<T> SliceExt for Slice<T> {
321    type Item = T;
322
323    /// create SliceFnInitializer
324    #[inline(always)]
325    fn fn_init<F>(size: usize, f: F) -> impl EmplaceInitializer<Output = [Self::Item]>
326    where
327        F: FnMut() -> Self::Item,
328    {
329        SliceFnInitializer::new(size, f)
330    }
331
332    /// create SliceIterInitializer
333    fn iter_init<Iter>(size: usize, iter: Iter) -> impl EmplaceInitializer<Output = [Self::Item]>
334    where
335        Iter: Iterator<Item = Self::Item>,
336    {
337        SliceIterInitializer::new(size, iter)
338    }
339}
340
341pub struct RawInitializer<Output:?Sized, F>{
342    layout:Layout,
343    emplacer:F,
344    phan:PhantomData<Output>,
345}
346
347impl<Output, F> RawInitializer<Output,F>
348    where Output:?Sized, F:FnOnce(NonNull<u8>)->NonNull<Output>
349{
350    pub fn new(layout:Layout, f:F)->Self{
351        Self{
352            layout,
353            emplacer:f,
354            phan:Default::default()
355        }
356    }
357}
358
359impl<Output, F> EmplaceInitializer for RawInitializer<Output, F>
360    where Output:?Sized, F:FnOnce(NonNull<u8>)->NonNull<Output>
361{
362    type Output = Output;
363
364    fn layout(&mut self) -> Layout {
365        self.layout
366    }
367
368    fn emplace(self, ptr: NonNull<u8>) -> NonNull<Self::Output> {
369        (self.emplacer)(ptr)
370    }
371}
372
373#[cfg(test)]
374pub mod test {
375    use crate::{self as dst_init, RawInitializer};
376    use crate::{
377        CoercionInitializer, DirectInitializer, EmplaceInitializer,
378        SliceFnInitializer, SliceIterInitializer,
379    };
380    use dst_init_macros::dst;
381    use std::alloc;
382    use std::alloc::Layout;
383    use std::fmt::{Debug, Formatter};
384    use std::ptr::NonNull;
385
386    #[dst]
387    #[derive(Debug)]
388    struct Test<A, B, C, D> {
389        a: A,
390        b: B,
391        c: C,
392        dst: [(C, D)],
393    }
394
395    #[dst]
396    #[derive(Debug)]
397    struct Test1<A, B, C, D> {
398        a: usize,
399        t: Test<A, B, C, D>,
400    }
401
402    #[test]
403    fn test() {
404        let t = TestInit {
405            a: 1usize,
406            b: 1u8,
407            c: 1u8,
408            dst: SliceIterInitializer::new(3, (0..).map(|i| (i as u8, i as usize))),
409        };
410        let u = Test1Init { a: 1usize, t };
411        let a = alloc(u);
412        println!("{:?}", a)
413    }
414
415    fn alloc<O: ?Sized, Init: EmplaceInitializer<Output = O>>(mut init: Init) -> Box<O> {
416        unsafe {
417            let layout = init.layout();
418            let ptr = alloc::alloc(layout);
419            if ptr.is_null() {
420                panic!("no memory");
421            }
422            let ptr = init.emplace(NonNull::new(ptr).unwrap());
423            Box::from_raw(ptr.as_ptr())
424        }
425    }
426
427    #[derive(PartialEq, Copy, Clone)]
428    pub struct FstStruct {
429        a: u8,
430        b: usize,
431        c: f64,
432    }
433    impl Debug for FstStruct {
434        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
435            write!(f, "{},{},{}", self.a, self.b, self.c)
436        }
437    }
438
439    #[allow(dead_code)]
440    #[derive(Debug)]
441    pub struct DstStruct<Data: Debug + ?Sized> {
442        a: u8,
443        b: usize,
444        c: u8,
445        d: Data,
446    }
447
448    #[test]
449    fn test_direct_initializer() {
450        #[inline(never)]
451        fn test<T: PartialEq + Debug>(a: T, b: T) {
452            let mut init = DirectInitializer::new(a);
453            let layout = init.layout();
454            assert_eq!(layout, Layout::new::<T>());
455            let obj = alloc(init);
456            assert_eq!(*obj, b);
457        }
458
459        test(12345usize, 12345usize);
460        test(127u8, 127u8);
461        test(456131248u32, 456131248u32);
462        test(4123456789u64, 4123456789u64);
463        test(1.0f64, 1.0f64);
464
465        let a = FstStruct {
466            a: 159,
467            b: 47521,
468            c: 12345.12345,
469        };
470        test(a, a);
471    }
472
473    #[test]
474    fn test_coercion_initializer() {
475        let a = FstStruct {
476            a: 159,
477            b: 47521,
478            c: 12345.12345,
479        };
480        let init = CoercionInitializer::new(a);
481        let data: Box<dyn Debug> = alloc(init);
482        assert_eq!(format!("{:?}", &*data), "159,47521,12345.12345");
483
484        let create = || DstStruct {
485            a: 156,
486            b: 157,
487            c: 175,
488            d: [1usize, 13123usize, 13123usize],
489        };
490        let init = CoercionInitializer::new(create());
491        let data: Box<DstStruct<[usize]>> = alloc(init);
492        assert_eq!(format!("{:?}", data), format!("{:?}", create()));
493    }
494
495    #[test]
496    fn test_slice_fn_initializer() {
497        let mut i = 0;
498        let init = SliceFnInitializer::new(10065, || {
499            i += 1;
500            i
501        });
502        let data = alloc(init);
503        i = 1;
504        for x in data.iter() {
505            assert_eq!(i, *x);
506            i += 1;
507        }
508    }
509
510    #[test]
511    fn test_slice_iter_initializer() {
512        let init = SliceIterInitializer::new(100, 0..100);
513        let data = alloc(init);
514        for x in 0..100 {
515            assert_eq!(data[x], x)
516        }
517    }
518
519    #[test]
520    fn test_raw_initializer(){
521        let init = RawInitializer::new(Layout::new::<[u8;10]>(),|ptr|{unsafe{
522            let mut ptr = ptr.as_ptr();
523            let tmp = ptr;
524            for x in 0..10{
525                *ptr = x as u8;
526                ptr = ptr.add(1);
527            }
528            return NonNull::new(std::ptr::slice_from_raw_parts_mut(tmp, 10)).expect("error when creating NonNull");
529        }});
530        let data = alloc(init);
531        for x in 0..10 {
532            assert_eq!(data[x], x as u8)
533        }
534    }
535}