Skip to main content

jlrs/data/layout/
typed_layout.rs

1//! Fully-typed layout.
2//!
3//! Layouts don't necessarily use all type parameters of a Julia type, for example when a
4//! parameter is a value type or is only used by fields which have a mutable type. This means the
5//! layout can't implement [`ConstructType`], which is necessary to convert that data into a
6//! [`Value`].
7//!
8//! For this purpose [`TypedLayout`] and [`HasLayout`] exist. A `TypedLayout` wraps a layout and
9//! a type constructor, `HasLayout` declares what layouts are associated with a type constructor.
10//! This trait is automatically implemented when a type implements both [`ValidLayout`] and
11//! [`ConstructType`].
12//!
13//! [`Value`]: crate::data::managed::value::Value
14
15use std::{fmt, marker::PhantomData};
16
17use super::{
18    is_bits::IsBits,
19    valid_layout::{ValidField, ValidLayout},
20};
21use crate::{
22    convert::{
23        ccall_types::{CCallArg, CCallReturn},
24        unbox::Unbox,
25    },
26    data::types::{construct_type::ConstructType, typecheck::Typecheck},
27    prelude::{DataType, LocalScope, Managed, Target, Value},
28};
29
30/// Associate a layout with a type constructor.
31///
32/// Safety:
33///
34/// `Layout` must be a valid layout for the type constructor.
35pub unsafe trait HasLayout<'scope, 'data>: ConstructType {
36    /// The layout associated with this type constructor.
37    type Layout: ValidLayout;
38}
39
40unsafe impl<'scope, 'data, T: ConstructType + ValidLayout> HasLayout<'scope, 'data> for T {
41    type Layout = T;
42}
43
44/// A layout annotated with its type constructor.
45#[repr(transparent)]
46pub struct TypedLayout<L, T> {
47    data: L,
48    _ty: PhantomData<T>,
49}
50
51impl<L, T> TypedLayout<L, T>
52where
53    L: ValidField,
54    T: ConstructType,
55{
56    /// Convert `data` to a `TypedLayout` with an arbitrary type constructor `T`.
57    ///
58    /// Safety: `L` must be a valid layout for `T`.
59    #[inline]
60    pub const unsafe fn new_relaxed(data: L) -> Self {
61        TypedLayout {
62            data,
63            _ty: PhantomData,
64        }
65    }
66
67    /// Convert a typed layout to its layout.
68    #[inline]
69    pub fn into_layout(self) -> L {
70        self.data
71    }
72}
73
74impl<'scope, 'data, T> TypedLayout<T::Layout, T>
75where
76    T: HasLayout<'scope, 'data>,
77{
78    /// Convert `data` to a `TypedLayout`.
79    #[inline]
80    pub const fn new(data: T::Layout) -> Self {
81        TypedLayout {
82            data,
83            _ty: PhantomData,
84        }
85    }
86}
87
88unsafe impl<L, T> IsBits for TypedLayout<L, T>
89where
90    L: IsBits + ValidLayout,
91    T: 'static + HasLayout<'static, 'static, Layout = L>,
92{
93}
94
95impl<L, T> Clone for TypedLayout<L, T>
96where
97    L: Clone,
98{
99    fn clone(&self) -> Self {
100        Self {
101            data: self.data.clone(),
102            _ty: PhantomData,
103        }
104    }
105}
106
107impl<L, T> fmt::Debug for TypedLayout<L, T>
108where
109    L: fmt::Debug,
110{
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        f.debug_struct("TypedLayout")
113            .field("data", &self.data)
114            .finish()
115    }
116}
117
118unsafe impl<L, T> Typecheck for TypedLayout<L, T>
119where
120    L: Typecheck,
121    T: ConstructType,
122{
123    fn typecheck(t: DataType) -> bool {
124        t.unrooted_target().local_scope::<_, 1>(|mut frame| {
125            let ty = T::construct_type(&mut frame);
126            if ty != t {
127                return false;
128            }
129
130            L::typecheck(t)
131        })
132    }
133}
134
135unsafe impl<L, T> ValidLayout for TypedLayout<L, T>
136where
137    L: ValidLayout,
138    T: ConstructType,
139{
140    fn valid_layout(t: Value) -> bool {
141        t.unrooted_target().local_scope::<_, 1>(|mut frame| {
142            let ty = T::construct_type(&mut frame);
143            if ty != t {
144                return false;
145            }
146
147            L::valid_layout(t)
148        })
149    }
150
151    fn type_object<'target, Tgt: Target<'target>>(target: &Tgt) -> Value<'target, 'static> {
152        L::type_object(target)
153    }
154}
155
156unsafe impl<L, T> ValidField for TypedLayout<L, T>
157where
158    L: ValidField,
159    T: ConstructType,
160{
161    fn valid_field(t: Value) -> bool {
162        t.unrooted_target().local_scope::<_, 1>(|mut frame| {
163            let ty = T::construct_type(&mut frame);
164            if ty != t {
165                return false;
166            }
167
168            L::valid_field(t)
169        })
170    }
171}
172
173unsafe impl<L, T> Unbox for TypedLayout<L, T>
174where
175    L: Clone,
176    T: ConstructType,
177{
178    type Output = Self;
179}
180
181unsafe impl<L, T> ConstructType for TypedLayout<L, T>
182where
183    T: ConstructType,
184{
185    type Static = T::Static;
186
187    #[inline]
188    fn construct_type_uncached<'target, Tgt>(
189        target: Tgt,
190    ) -> crate::prelude::ValueData<'target, 'static, Tgt>
191    where
192        Tgt: Target<'target>,
193    {
194        T::construct_type_uncached(target)
195    }
196
197    #[inline]
198    fn construct_type_with_env_uncached<'target, Tgt>(
199        target: Tgt,
200        env: &crate::data::types::construct_type::TypeVarEnv,
201    ) -> crate::prelude::ValueData<'target, 'static, Tgt>
202    where
203        Tgt: Target<'target>,
204    {
205        T::construct_type_with_env_uncached(target, env)
206    }
207
208    #[inline]
209    fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
210    where
211        Tgt: Target<'target>,
212    {
213        T::base_type(target)
214    }
215}
216
217unsafe impl<L, T> CCallArg for TypedLayout<L, T>
218where
219    L: IsBits,
220    T: ConstructType,
221{
222    type CCallArgType = Self;
223    type FunctionArgType = Self;
224}
225
226unsafe impl<L, T> CCallReturn for TypedLayout<L, T>
227where
228    L: IsBits,
229    T: ConstructType,
230{
231    type FunctionReturnType = Self;
232    type CCallReturnType = Self;
233    type ReturnAs = Self;
234
235    #[inline]
236    unsafe fn return_or_throw(self) -> Self::ReturnAs {
237        self
238    }
239}