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
//! Fully-typed layout.
//!
//! Layouts don't necessarily use all type parameters of a Julia type, for example when a
//! parameter is a value type or is only used by fields which have a mutable type. This means the
//! layout can't implement [`ConstructType`], which is necessary to convert that data into a
//! [`Value`].
//!
//! For this purpose [`TypedLayout`] and [`HasLayout`] exist. A `TypedLayout` wraps a layout and
//! a type constructor, `HasLayout` declares what layouts are associated with a type constructor.
//! This trait is automatically implemented when a type implements both [`ValidLayout`] and
//! [`ConstructType`],
//!
//! [`Value`]: crate::data::managed::value::Value

use std::marker::PhantomData;

use super::{is_bits::IsBits, valid_layout::ValidLayout};
use crate::data::types::construct_type::ConstructType;

/// Associate a layout with a type constructor.
///
/// Safety:
///
/// `Layout` must be a valid layout for the type constructor.
pub unsafe trait HasLayout<'scope, 'data>: ConstructType {
    /// The layout associated with this type constructor.
    type Layout: ValidLayout;
}

unsafe impl<'scope, 'data, T: ConstructType + ValidLayout> HasLayout<'scope, 'data> for T {
    type Layout = T;
}

/// A layout annotated with its type constructor.
#[repr(transparent)]
pub struct TypedLayout<L: ValidLayout, T: ConstructType> {
    data: L,
    _ty: PhantomData<T>,
}

impl<L, T> TypedLayout<L, T>
where
    L: ValidLayout,
    T: ConstructType,
{
    /// Convert `data` to a `TypedLayout` with an arbitrary type constructor `T`.
    #[inline]
    pub const fn new_relaxed(data: L) -> Self {
        TypedLayout {
            data,
            _ty: PhantomData,
        }
    }

    /// Convert a typed layout to its layout.
    #[inline]
    pub fn into_layout(self) -> L {
        self.data
    }
}

impl<'scope, 'data, T> TypedLayout<T::Layout, T>
where
    T: HasLayout<'scope, 'data>,
{
    /// Convert `data` to a `TypedLayout`.
    #[inline]
    pub const fn new(data: T::Layout) -> Self {
        TypedLayout {
            data,
            _ty: PhantomData,
        }
    }
}

unsafe impl<L: IsBits + ValidLayout, T: 'static + HasLayout<'static, 'static, Layout = L>> IsBits
    for TypedLayout<L, T>
{
}

// TODO: other traits