jlrs/data/types/
typecheck.rs1use std::{ffi::c_void, marker::PhantomData};
13
14use jl_sys::jl_string_type;
16
17use super::abstract_type::AbstractType;
18use crate::{
19 convert::into_julia::IntoJulia,
20 data::managed::{Managed, datatype::DataType, type_name::TypeName, union_all::UnionAll},
21 memory::target::unrooted::Unrooted,
22 prelude::LocalScope,
23};
24
25#[diagnostic::on_unimplemented(
36 message = "the trait bound `{Self}: Typecheck` is not satisfied",
37 label = "the trait `Typecheck` is not implemented for `{Self}`",
38 note = "Custom types that implement `Typecheck` should be generated with JlrsCore.reflect",
39 note = "Do not implement `ForeignType` or `OpaqueType` unless this type is exported to Julia with `julia_module!`"
40)]
41pub unsafe trait Typecheck {
42 fn typecheck(t: DataType) -> bool;
44}
45
46pub struct AbstractTypecheck<A: AbstractType>(PhantomData<A>);
50
51unsafe impl<A: AbstractType> Typecheck for AbstractTypecheck<A> {
52 fn typecheck(t: DataType) -> bool {
53 t.unrooted_target().local_scope::<_, 1>(|mut frame| {
54 let ty = A::construct_type(&mut frame);
55 t.as_value().subtype(ty)
56 })
57 }
58}
59
60#[doc(hidden)]
61#[macro_export]
62macro_rules! impl_julia_typecheck {
63 ($type:ty, $jl_type:expr_2021, $($lt:lifetime),+) => {
64 unsafe impl<$($lt),+> crate::data::types::typecheck::Typecheck for $type {
65 #[inline]
66 fn typecheck(t: $crate::data::managed::datatype::DataType) -> bool {
67 unsafe {
68 <$crate::data::managed::datatype::DataType as $crate::data::managed::private::ManagedPriv>::unwrap(t, crate::private::Private) == $jl_type
69 }
70 }
71 }
72 };
73 ($type:ty, $jl_type:expr_2021) => {
74 unsafe impl crate::data::types::typecheck::Typecheck for $type {
75 #[inline]
76 fn typecheck(t: $crate::data::managed::datatype::DataType) -> bool {
77 unsafe {
78 <$crate::data::managed::datatype::DataType as $crate::data::managed::private::ManagedPriv>::unwrap(t, crate::private::Private) == $jl_type
79 }
80 }
81 }
82 };
83 ($type:ty) => {
84 unsafe impl crate::data::types::typecheck::Typecheck for $type {
85 #[inline]
86 fn typecheck(t: crate::data::managed::datatype::DataType) -> bool {
87 unsafe {
88 let global = $crate::memory::target::unrooted::Unrooted::new();
89 <$crate::data::managed::datatype::DataType as $crate::data::managed::private::ManagedPriv>::unwrap(t, crate::private::Private) == <$type as $crate::convert::into_julia::IntoJulia>::julia_type(global).ptr().as_ptr()
90 }
91 }
92 }
93 };
94}
95
96impl_julia_typecheck!(i8);
97impl_julia_typecheck!(i16);
98impl_julia_typecheck!(i32);
99impl_julia_typecheck!(i64);
100impl_julia_typecheck!(isize);
101impl_julia_typecheck!(u8);
102impl_julia_typecheck!(u16);
103impl_julia_typecheck!(u32);
104impl_julia_typecheck!(u64);
105impl_julia_typecheck!(usize);
106impl_julia_typecheck!(f32);
107impl_julia_typecheck!(f64);
108impl_julia_typecheck!(bool);
109impl_julia_typecheck!(char);
110impl_julia_typecheck!(*mut c_void);
111
112unsafe impl<T: IntoJulia> Typecheck for *mut T {
113 #[inline]
114 fn typecheck(t: DataType) -> bool {
115 unsafe {
116 let global = Unrooted::new();
117 let ptr_tname = TypeName::of_pointer(&global);
118
119 if t.type_name() != ptr_tname {
120 return false;
121 }
122
123 let params = t.parameters();
124 let param = params.data().get(global, 0);
125 let inner_ty = T::julia_type(global);
126 if param.unwrap_unchecked().as_value() != inner_ty.as_value() {
127 return false;
128 }
129
130 true
131 }
132 }
133}
134
135pub struct Type;
139unsafe impl Typecheck for Type {
140 #[inline]
141 fn typecheck(t: DataType) -> bool {
142 t.as_value().is_kind()
143 }
144}
145
146pub struct Bits;
149unsafe impl Typecheck for Bits {
150 #[inline]
151 fn typecheck(t: DataType) -> bool {
152 t.is_bits()
153 }
154}
155
156pub struct Abstract;
159unsafe impl Typecheck for Abstract {
160 #[inline]
161 fn typecheck(t: DataType) -> bool {
162 t.is_abstract()
163 }
164}
165
166pub struct AbstractRef;
169unsafe impl Typecheck for AbstractRef {
170 fn typecheck(t: DataType) -> bool {
171 unsafe {
172 t.type_name()
173 == UnionAll::ref_type(&Unrooted::new())
174 .body()
175 .cast_unchecked::<DataType>()
176 .type_name()
177 }
178 }
179}
180
181pub struct VecElement;
184unsafe impl Typecheck for VecElement {
185 #[inline]
186 fn typecheck(t: DataType) -> bool {
187 unsafe { t.type_name() == TypeName::of_vecelement(&Unrooted::new()) }
188 }
189}
190
191pub struct TypeType;
194unsafe impl Typecheck for TypeType {
195 fn typecheck(t: DataType) -> bool {
196 unsafe {
197 t.type_name()
198 == UnionAll::type_type(&Unrooted::new())
199 .body()
200 .cast_unchecked::<DataType>()
201 .type_name()
202 }
203 }
204}
205
206pub struct Mutable;
209unsafe impl Typecheck for Mutable {
210 #[inline]
211 fn typecheck(t: DataType) -> bool {
212 t.mutable()
213 }
214}
215
216pub struct Immutable;
219unsafe impl Typecheck for Immutable {
220 #[inline]
221 fn typecheck(t: DataType) -> bool {
222 !t.mutable()
223 }
224}
225
226pub struct PrimitiveType;
229unsafe impl Typecheck for PrimitiveType {
230 fn typecheck(t: DataType) -> bool {
231 unsafe {
232 t.is::<Immutable>()
233 && t.has_layout()
234 && t.n_fields().unwrap_unchecked() == 0
235 && t.size().unwrap_unchecked() > 0
236 }
237 }
238}
239
240pub struct StructType;
243unsafe impl Typecheck for StructType {
244 #[inline]
245 fn typecheck(t: DataType) -> bool {
246 !t.is_abstract() && !t.is::<PrimitiveType>()
247 }
248}
249
250pub struct Singleton;
253unsafe impl Typecheck for Singleton {
254 #[inline]
255 fn typecheck(t: DataType) -> bool {
256 t.instance().is_some()
257 }
258}
259
260impl_julia_typecheck!(String, jl_string_type);
261
262pub struct Pointer;
265unsafe impl Typecheck for Pointer {
266 #[inline]
267 fn typecheck(t: DataType) -> bool {
268 unsafe { t.type_name() == TypeName::of_pointer(&Unrooted::new()) }
269 }
270}
271
272pub struct LLVMPointer;
275unsafe impl Typecheck for LLVMPointer {
276 #[inline]
277 fn typecheck(t: DataType) -> bool {
278 unsafe { t.type_name() == TypeName::of_llvmpointer(&Unrooted::new()) }
279 }
280}
281
282pub struct Concrete;
285unsafe impl Typecheck for Concrete {
286 #[inline]
287 fn typecheck(t: DataType) -> bool {
288 t.is_concrete_type()
289 }
290}