1use std::{any::TypeId, ffi::c_void, marker::PhantomData, ptr::NonNull, string::FromUtf8Error};
4
5use fnv::FnvHashMap;
6use jl_sys::{
7 jl_bool_type, jl_bottom_type, jl_char_type, jl_float32_type, jl_float64_type, jl_int8_type,
8 jl_int16_type, jl_int32_type, jl_int64_type, jl_pointer_type, jl_uint8_type, jl_uint16_type,
9 jl_uint32_type, jl_uint64_type, jl_uniontype_type, jl_value_t, jl_voidpointer_type,
10};
11use rustc_hash::FxHashSet;
12
13use super::abstract_type::{AbstractType, AnyType};
14use crate::{
15 convert::to_symbol::ToSymbol,
16 data::{
17 cache::Cache,
18 layout::{is_bits::IsBits, tuple::Tuple, typed_layout::HasLayout},
19 managed::{
20 Managed,
21 array::dimensions::DimsExt,
22 datatype::DataType,
23 simple_vector::SimpleVector,
24 type_var::{TypeVar, TypeVarData},
25 union::Union,
26 union_all::UnionAll,
27 value::{Value, ValueData, ValueUnbound},
28 },
29 },
30 memory::{
31 PTls,
32 scope::{LocalScope, LocalScopeExt},
33 target::{RootingTarget, Target, unrooted::Unrooted},
34 },
35 prelude::{ConstructTypedArray, Symbol, WeakValue},
36 private::Private,
37};
38
39type CacheImpl = ConstructedTypes;
40
41static CONSTRUCTED_TYPE_CACHE: CacheImpl = CacheImpl::new();
42
43pub(crate) unsafe fn mark_constructed_type_cache(ptls: PTls, full: bool) {
44 unsafe {
45 CONSTRUCTED_TYPE_CACHE.data.mark(ptls, full);
46 }
47}
48
49#[macro_export]
53macro_rules! define_fast_key {
54 ($(#[$meta:meta])* $vis:vis $ty:ident, $for_ty:ty) => {
55 $(#[$meta])*
56 $vis struct $ty;
57
58 unsafe impl $crate::data::types::construct_type::FastKey for $ty {
59 type For = $for_ty;
60
61 #[inline]
62 fn construct_type_fast<'target, Tgt>(
63 target: &Tgt,
64 ) -> $crate::data::managed::value::Value<'target, 'static>
65 where
66 Tgt: $crate::memory::target::Target<'target>,
67 {
68 static REF: $crate::data::static_data::StaticConstructibleType<$for_ty> =
69 $crate::data::static_data::StaticConstructibleType::<$for_ty>::new();
70 REF.get_or_init(&target)
71 }
72 }
73 };
74}
75
76#[macro_export]
80macro_rules! define_fast_array_key {
81 ($(#[$meta:meta])* $vis:vis $ty:ident, $elem_ty:ty, $rank:literal) => {
82 $(#[$meta])*
83 $vis struct $ty;
84
85 unsafe impl $crate::data::types::construct_type::FastKey for $ty {
86 type For = $crate::data::managed::array::TypedRankedArray<
87 'static,
88 'static,
89 <$elem_ty as $crate::data::types::construct_type::ConstructType>::Static,
90 $rank
91 >;
92
93 #[inline]
94 fn construct_type_fast<'target, Tgt>(
95 target: &Tgt,
96 ) -> $crate::data::managed::value::Value<'target, 'static>
97 where
98 Tgt: $crate::memory::target::Target<'target>,
99 {
100 type Ty = $crate::data::types::construct_type::RankedArrayType<$elem_ty, $rank>;
101 static REF: $crate::data::static_data::StaticConstructibleType<Ty> =
102 $crate::data::static_data::StaticConstructibleType::<Ty>::new();
103 REF.get_or_init(&target)
104 }
105 }
106
107 unsafe impl $crate::data::types::construct_type::FastArrayKey<$rank> for $ty {
108 type ElemType = $elem_ty;
109 }
110 };
111}
112
113#[macro_export]
131macro_rules! tvar {
132 ($name:ty) => {
133 $crate::data::types::construct_type::TypeVarConstructor::<$name>
134 };
135 ($name:literal) => {
136 $crate::data::types::construct_type::TypeVarConstructor::<
137 $crate::data::types::construct_type::Name<$name>,
138 >
139 };
140 ($name:literal; $ub:ty) => {
141 $crate::data::types::construct_type::TypeVarConstructor::<
142 $crate::data::types::construct_type::Name<$name>,
143 $ub,
144 >
145 };
146 ($name:ty; $ub:ty) => {
147 $crate::data::types::construct_type::TypeVarConstructor::<$name, $ub>
148 };
149 ($lb:ty; $name:literal; $ub:ty) => {
150 $crate::data::types::construct_type::TypeVarConstructor::<
151 $crate::data::types::construct_type::Name<$name>,
152 $ub,
153 $lb,
154 >
155 };
156 ($lb:ty; $name:ty; $ub:ty) => {
157 $crate::data::types::construct_type::TypeVarConstructor::<$name, $ub, $lb>
158 };
159}
160
161#[macro_export]
173macro_rules! tvars {
174 ($t:ty) => {
175 $t
176 };
177 ($t1:ty, $R:ty) => {
178 $crate::data::types::construct_type::TypeVarFragment<$t1, $R>
179 };
180 ($t1:ty, $R:ty, $($rest:ty),+) => {
181 $crate::data::types::construct_type::TypeVarFragment<$t1, tvars!($R, $($rest),+)>
182 };
183}
184
185#[macro_export]
189macro_rules! bytes {
190 ($t1:literal, $R:literal) => {
191 $crate::data::types::construct_type::ConstantBytes<
192 $crate::data::types::construct_type::ConstantU8<$t1>,
193 $crate::data::types::construct_type::ConstantU8<$R>
194 >
195 };
196 ($t1:literal, $R:literal, $($rest:literal),+) => {
197 $crate::data::types::construct_type::ConstantBytes<
198 $crate::data::types::construct_type::ConstantU8<$t1>,
199 $crate::bytes!($R, $($rest),+)
200 >
201 };
202}
203
204#[diagnostic::on_unimplemented(
211 message = "the trait bound `{Self}: ConstructType` is not satisfied",
212 label = "the trait `ConstructType` is not implemented for `{Self}`",
213 note = "Custom types that implement `ConstructType` should be generated with JlrsCore.reflect",
214 note = "Do not implement `ForeignType` or `OpaqueType` unless this type is exported to Julia with `julia_module!`"
215)]
216
217pub unsafe trait ConstructType: Sized {
218 type Static: 'static + ConstructType;
221
222 const CACHEABLE: bool = true;
228
229 #[inline(always)]
231 fn type_id() -> TypeId {
232 TypeId::of::<Self::Static>()
233 }
234
235 #[inline]
238 fn construct_type<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
239 where
240 Tgt: Target<'target>,
241 {
242 if Self::CACHEABLE {
243 unsafe {
244 CONSTRUCTED_TYPE_CACHE
245 .find_or_construct::<Self>()
246 .root(target)
247 }
248 } else {
249 Self::construct_type_uncached(target)
250 }
251 }
252
253 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
255 where
256 Tgt: Target<'target>;
257
258 #[inline]
265 fn construct_type_with_env<'target, Tgt>(
266 target: Tgt,
267 env: &TypeVarEnv,
268 ) -> ValueData<'target, 'static, Tgt>
269 where
270 Tgt: Target<'target>,
271 {
272 if Self::CACHEABLE {
273 unsafe {
274 CONSTRUCTED_TYPE_CACHE
275 .find_or_construct_with_env::<Self>(env)
276 .root(target)
277 }
278 } else {
279 Self::construct_type_with_env_uncached(target, env)
280 }
281 }
282
283 fn construct_type_with_env_uncached<'target, Tgt>(
288 target: Tgt,
289 env: &TypeVarEnv,
290 ) -> ValueData<'target, 'static, Tgt>
291 where
292 Tgt: Target<'target>;
293
294 fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
300 where
301 Tgt: Target<'target>;
302}
303
304pub struct IfConcreteElse<T1: ConstructType, T2: ConstructType> {
307 _marker: PhantomData<(T1, T2)>,
308}
309
310unsafe impl<T1: ConstructType, T2: ConstructType> ConstructType for IfConcreteElse<T1, T2> {
311 type Static = IfConcreteElse<T1::Static, T2::Static>;
312
313 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
314 where
315 Tgt: Target<'target>,
316 {
317 let t1 = T1::construct_type(&target);
318 unsafe {
319 let v = t1.as_value();
320 if v.is::<DataType>() {
321 if v.cast_unchecked::<DataType>().is_concrete_type() {
322 return t1.root(target);
323 }
324 }
325
326 T2::construct_type(target)
327 }
328 }
329
330 fn construct_type_with_env_uncached<'target, Tgt>(
331 target: Tgt,
332 env: &crate::data::types::construct_type::TypeVarEnv,
333 ) -> ValueData<'target, 'static, Tgt>
334 where
335 Tgt: Target<'target>,
336 {
337 let t1 = T1::construct_type_with_env_uncached(&target, env);
338 unsafe {
339 let v = t1.as_value();
340 if v.is::<DataType>() {
341 if v.cast_unchecked::<DataType>().is_concrete_type() {
342 return t1.root(target);
343 }
344 }
345
346 T2::construct_type_with_env_uncached(target, env)
347 }
348 }
349
350 fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
351 where
352 Tgt: Target<'target>,
353 {
354 let t1 = T1::construct_type(&target);
355 unsafe {
356 let v = t1.as_value();
357 if v.is::<DataType>() {
358 if v.cast_unchecked::<DataType>().is_concrete_type() {
359 return T1::base_type(target);
360 }
361 }
362
363 T2::base_type(target)
364 }
365 }
366}
367
368pub unsafe trait FastKey: 'static {
399 type For: ConstructType;
400 fn construct_type_fast<'target, Tgt>(target: &Tgt) -> Value<'target, 'static>
401 where
402 Tgt: Target<'target>;
403}
404
405pub unsafe trait FastArrayKey<const N: isize>: 'static + FastKey {
437 type ElemType: ConstructType;
439
440 const ASSERT_VALID_RANK: () = assert!(N >= 0, "Array rank must be non-negative");
442}
443
444impl<T: FastArrayKey<N>, const N: isize> ConstructTypedArray<T::ElemType, N> for T {
445 #[inline]
446 fn array_type<'target, D, Tgt>(target: Tgt, _dims: &D) -> ValueData<'target, 'static, Tgt>
447 where
448 Tgt: Target<'target>,
449 D: DimsExt,
450 {
451 let _ = Self::ASSERT_VALID_RANK;
452 Key::<T>::construct_type(target)
453 }
454}
455
456pub struct Key<K: FastKey>(PhantomData<K>);
460
461unsafe impl<K: FastKey> ConstructType for Key<K> {
462 type Static = <K::For as ConstructType>::Static;
463 const CACHEABLE: bool = false;
464
465 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
466 where
467 Tgt: Target<'target>,
468 {
469 K::construct_type_fast(&target).root(target)
470 }
471
472 fn construct_type_with_env_uncached<'target, Tgt>(
473 target: Tgt,
474 _env: &TypeVarEnv,
475 ) -> ValueData<'target, 'static, Tgt>
476 where
477 Tgt: Target<'target>,
478 {
479 K::construct_type_fast(&target).root(target)
480 }
481
482 fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
483 where
484 Tgt: Target<'target>,
485 {
486 unsafe {
487 let v = K::construct_type_fast(target);
488 if v.is::<DataType>() {
489 let dt = v.cast_unchecked::<DataType>();
490 Some(dt.type_name().wrapper())
491 } else {
492 Some(v)
493 }
494 }
495 }
496}
497
498unsafe impl<K> AbstractType for Key<K>
499where
500 K: FastKey,
501 K::For: AbstractType,
502{
503}
504
505pub trait TypeVars {
508 const SIZE: usize;
510
511 fn into_env<'target, Tgt: RootingTarget<'target>>(target: Tgt) -> TypeVarEnv<'target>;
514
515 #[doc(hidden)]
516 fn extend_env<'target, Tgt: Target<'target>>(target: &Tgt, env: &mut TypeVarEnv, offset: usize);
518}
519
520impl<N: TypeVarName, U: ConstructType, L: ConstructType> TypeVars for TypeVarConstructor<N, U, L> {
521 const SIZE: usize = 1;
522
523 fn into_env<'target, Tgt: RootingTarget<'target>>(target: Tgt) -> TypeVarEnv<'target> {
524 target.with_local_scope::<_, 1>(|target, mut frame| {
525 let svec = SimpleVector::with_capacity(&mut frame, Self::SIZE);
526 let mut env = TypeVarEnv { svec };
527
528 Self::extend_env(&frame, &mut env, 0);
529
530 let svec = Tgt::into_concrete_type(svec.root(target));
531 TypeVarEnv { svec }
532 })
533 }
534
535 fn extend_env<'target, Tgt: Target<'target>>(
536 target: &Tgt,
537 env: &mut TypeVarEnv,
538 offset: usize,
539 ) {
540 target.local_scope::<_, 1>(|mut frame| {
541 let sym = N::symbol(&frame);
542 if let Some(_) = env.get(sym) {
543 panic!("Duplicate tvar");
544 }
545
546 let tvar = Self::new(&mut frame, env);
547 env.set(offset, tvar);
548 })
549 }
550}
551
552pub struct TypeVarFragment<T1: TypeVars, R: TypeVars>(PhantomData<T1>, PhantomData<R>);
560
561impl<T1: TypeVars, R: TypeVars> TypeVars for TypeVarFragment<T1, R> {
562 const SIZE: usize = T1::SIZE + R::SIZE;
563
564 fn into_env<'target, Tgt: RootingTarget<'target>>(target: Tgt) -> TypeVarEnv<'target> {
565 target.with_local_scope::<_, 1>(|target, mut frame| {
566 let svec = SimpleVector::with_capacity(&mut frame, Self::SIZE);
567 let mut env = TypeVarEnv { svec };
568
569 T1::extend_env(&frame, &mut env, 0);
570 R::extend_env(&frame, &mut env, T1::SIZE);
571
572 let svec = Tgt::into_concrete_type(svec.root(target));
573 TypeVarEnv { svec }
574 })
575 }
576
577 fn extend_env<'target, Tgt: Target<'target>>(
578 target: &Tgt,
579 env: &mut TypeVarEnv,
580 offset: usize,
581 ) {
582 T1::extend_env(target, env, offset);
583 R::extend_env(target, env, offset + T1::SIZE);
584 }
585}
586
587#[derive(Debug)]
589pub struct TypeVarEnv<'scope> {
590 svec: SimpleVector<'scope>,
591}
592
593impl<'scope> TypeVarEnv<'scope> {
594 pub fn get(&self, sym: Symbol) -> Option<TypeVar<'scope>> {
596 let unrooted = sym.unrooted_target();
597 let svec = self.svec.data();
598
599 (0..svec.len())
600 .filter_map(|idx| svec.get(unrooted, idx))
601 .map(|elem| unsafe { elem.as_value().cast_unchecked::<TypeVar>() })
602 .find(|elem| elem.name() == sym)
603 .map(|elem| unsafe { elem.as_weak().leak().as_managed() })
604 }
605
606 pub fn is_empty(&self) -> bool {
608 self.svec.len() == 0
609 }
610
611 pub fn empty<Tgt: Target<'scope>>(tgt: &Tgt) -> Self {
613 TypeVarEnv {
614 svec: SimpleVector::emptysvec(tgt),
615 }
616 }
617
618 pub fn to_svec(&self) -> SimpleVector<'scope> {
620 self.svec
621 }
622
623 fn set(&mut self, offset: usize, tvar: TypeVar) {
624 unsafe {
625 let len = self.svec.len();
626 assert!(offset < len);
627 let data = self.svec.data();
628 data.set(offset, Some(tvar.as_value())).unwrap();
629 }
630 }
631}
632
633macro_rules! impl_construct_julia_type_constant {
634 ($ty:ty, $const_ty:ty) => {
635 unsafe impl<const N: $const_ty> ConstructType for $ty {
636 type Static = $ty;
637
638 const CACHEABLE: bool = false;
639
640 #[inline]
641 fn construct_type_uncached<'target, Tgt>(
642 target: Tgt,
643 ) -> ValueData<'target, 'static, Tgt>
644 where
645 Tgt: Target<'target>,
646 {
647 Value::new(target, N)
648 }
649
650 #[inline]
651 fn construct_type_with_env_uncached<'target, Tgt>(
652 target: Tgt,
653 _: &TypeVarEnv,
654 ) -> ValueData<'target, 'static, Tgt>
655 where
656 Tgt: Target<'target>,
657 {
658 Value::new(target, N)
659 }
660
661 #[inline]
662 fn base_type<'target, Tgt>(_target: &Tgt) -> Option<Value<'target, 'static>>
663 where
664 Tgt: Target<'target>,
665 {
666 None
667 }
668 }
669 };
670}
671
672macro_rules! impl_construct_julia_type_constant_cached {
673 ($ty:ty, $const_ty:ty) => {
674 unsafe impl<const N: $const_ty> ConstructType for $ty {
675 type Static = $ty;
676
677 const CACHEABLE: bool = true;
678
679 #[inline]
680 fn construct_type_uncached<'target, Tgt>(
681 target: Tgt,
682 ) -> ValueData<'target, 'static, Tgt>
683 where
684 Tgt: Target<'target>,
685 {
686 Value::new(target, N)
687 }
688
689 #[inline]
690 fn construct_type_with_env_uncached<'target, Tgt>(
691 target: Tgt,
692 _: &TypeVarEnv,
693 ) -> ValueData<'target, 'static, Tgt>
694 where
695 Tgt: Target<'target>,
696 {
697 Value::new(target, N)
698 }
699
700 #[inline]
701 fn base_type<'target, Tgt>(_target: &Tgt) -> Option<Value<'target, 'static>>
702 where
703 Tgt: Target<'target>,
704 {
705 None
706 }
707 }
708 };
709}
710
711macro_rules! impl_construct_julia_type_primitive {
712 ($ty:ty, $jl_ty:ident) => {
713 unsafe impl ConstructType for $ty {
714 type Static = $ty;
715
716 const CACHEABLE: bool = false;
717
718 #[inline]
719 fn construct_type_uncached<'target, Tgt>(
720 target: Tgt,
721 ) -> ValueData<'target, 'static, Tgt>
722 where
723 Tgt: Target<'target>,
724 {
725 unsafe {
726 let ptr = NonNull::new_unchecked($jl_ty.cast::<jl_value_t>());
727 target.data_from_ptr(ptr, Private)
728 }
729 }
730
731 #[inline]
732 fn construct_type_with_env_uncached<'target, Tgt>(
733 target: Tgt,
734 _env: &TypeVarEnv,
735 ) -> ValueData<'target, 'static, Tgt>
736 where
737 Tgt: Target<'target>,
738 {
739 unsafe {
740 let ptr = NonNull::new_unchecked($jl_ty.cast::<jl_value_t>());
741 target.data_from_ptr(ptr, Private)
742 }
743 }
744
745 #[inline]
746 fn base_type<'target, Tgt>(_target: &Tgt) -> Option<Value<'target, 'static>>
747 where
748 Tgt: Target<'target>,
749 {
750 unsafe {
751 let ptr = NonNull::new_unchecked($jl_ty.cast::<jl_value_t>());
752 Some(
753 <Value as $crate::data::managed::private::ManagedPriv>::wrap_non_null(
754 ptr,
755 $crate::private::Private,
756 ),
757 )
758 }
759 }
760 }
761 };
762}
763
764pub struct ConstantI8<const N: i8>;
766impl_construct_julia_type_constant_cached!(ConstantI8<N>, i8);
767
768pub struct ConstantI16<const N: i16>;
770impl_construct_julia_type_constant!(ConstantI16<N>, i16);
771
772pub struct ConstantI32<const N: i32>;
774impl_construct_julia_type_constant!(ConstantI32<N>, i32);
775
776pub struct ConstantI64<const N: i64>;
778impl_construct_julia_type_constant!(ConstantI64<N>, i64);
779
780pub struct ConstantIsize<const N: isize>;
782impl_construct_julia_type_constant!(ConstantIsize<N>, isize);
783
784pub struct ConstantSize<const N: usize>;
786unsafe impl<const N: usize> ConstructType for ConstantSize<N> {
787 type Static = ConstantSize<N>;
788
789 const CACHEABLE: bool = false;
790
791 #[inline]
792 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
793 where
794 Tgt: Target<'target>,
795 {
796 Value::new(target, N as isize)
797 }
798
799 #[inline]
800 fn base_type<'target, Tgt>(_target: &Tgt) -> Option<Value<'target, 'static>>
801 where
802 Tgt: Target<'target>,
803 {
804 None
805 }
806
807 fn construct_type_with_env_uncached<'target, Tgt>(
808 target: Tgt,
809 _env: &TypeVarEnv,
810 ) -> ValueData<'target, 'static, Tgt>
811 where
812 Tgt: Target<'target>,
813 {
814 Value::new(target, N as isize)
815 }
816}
817
818pub struct ConstantU8<const N: u8>;
820impl_construct_julia_type_constant_cached!(ConstantU8<N>, u8);
821
822pub struct ConstantU16<const N: u16>;
824impl_construct_julia_type_constant!(ConstantU16<N>, u16);
825
826pub struct ConstantU32<const N: u32>;
828impl_construct_julia_type_constant!(ConstantU32<N>, u32);
829
830pub struct ConstantU64<const N: u64>;
832impl_construct_julia_type_constant!(ConstantU64<N>, u64);
833
834pub struct ConstantUsize<const N: usize>;
836impl_construct_julia_type_constant!(ConstantUsize<N>, usize);
837
838pub struct ConstantBool<const N: bool>;
840impl_construct_julia_type_constant!(ConstantBool<N>, bool);
841
842pub struct ConstantChar<const N: char>;
844impl_construct_julia_type_constant!(ConstantChar<N>, char);
845
846pub trait EncodedBytes: 'static {
848 type B: AsRef<[u8]>;
849 fn encoded_bytes() -> Self::B;
850}
851
852pub trait EncodedString: 'static {
854 type S: AsRef<str>;
855 fn encoded_string() -> Self::S;
856}
857
858pub trait ConstantStr: 'static {
861 const STR: &'static str;
863}
864
865impl<S: ConstantStr> EncodedString for S {
866 type S = &'static str;
867 fn encoded_string() -> Self::S {
868 Self::STR
869 }
870}
871
872pub trait ConstantByteSlice: 'static {
874 const BYTES: &'static [u8];
876}
877
878impl<S: ConstantByteSlice> EncodedBytes for S {
879 type B = &'static [u8];
880 fn encoded_bytes() -> Self::B {
881 Self::BYTES
882 }
883}
884
885pub trait ConstantBytesFragment: 'static {
887 const SIZE: usize;
889
890 #[doc(hidden)]
891 fn extend(slice: &mut [u8], offset: usize);
892}
893
894pub struct ConstantBytes<L: ConstantBytesFragment, R: ConstantBytesFragment>(
920 PhantomData<L>,
921 PhantomData<R>,
922);
923
924impl<L: ConstantBytesFragment, R: ConstantBytesFragment> ConstantBytes<L, R> {
925 pub fn into_vec() -> Vec<u8> {
927 let mut v = vec![0; Self::SIZE];
928 Self::extend(v.as_mut_slice(), 0);
929 v
930 }
931
932 pub fn into_string() -> Result<String, FromUtf8Error> {
934 let v = Self::into_vec();
935 String::from_utf8(v)
936 }
937}
938
939impl<L: ConstantBytesFragment, R: ConstantBytesFragment> EncodedBytes for ConstantBytes<L, R> {
940 type B = Vec<u8>;
941 fn encoded_bytes() -> Vec<u8> {
942 Self::into_vec()
943 }
944}
945
946impl<L: ConstantBytesFragment, R: ConstantBytesFragment> EncodedString for ConstantBytes<L, R> {
947 type S = String;
948 fn encoded_string() -> String {
949 Self::into_string().expect("Invalid string")
950 }
951}
952
953impl<L: ConstantBytesFragment, R: ConstantBytesFragment> TypeVarName for ConstantBytes<L, R> {
954 fn symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target> {
955 Self::into_string()
956 .expect("Invalid string")
957 .to_symbol(target)
958 }
959}
960
961impl<const N: u8> ConstantBytesFragment for ConstantU8<N> {
962 const SIZE: usize = 1;
963
964 #[inline]
965 fn extend(slice: &mut [u8], offset: usize) {
966 slice[offset] = N;
967 }
968}
969
970impl<L: ConstantBytesFragment, R: ConstantBytesFragment> ConstantBytesFragment
971 for ConstantBytes<L, R>
972{
973 const SIZE: usize = L::SIZE + R::SIZE;
974
975 #[inline]
976 fn extend(slice: &mut [u8], offset: usize) {
977 L::extend(slice, offset);
978 R::extend(slice, offset + L::SIZE);
979 }
980}
981
982pub struct Name<const N: char>;
984
985pub trait TypeVarName: 'static {
989 fn symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target>;
991}
992
993impl<const N: char> TypeVarName for Name<N> {
994 #[inline]
995 fn symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target> {
996 let mut bytes = [0; 4];
997 let s = N.encode_utf8(&mut bytes);
998 s.to_symbol(target)
999 }
1000}
1001
1002impl<const N: char> TypeVarName for ConstantChar<N> {
1003 #[inline]
1004 fn symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target> {
1005 let mut bytes = [0; 4];
1006 let s = N.encode_utf8(&mut bytes);
1007 s.to_symbol(target)
1008 }
1009}
1010
1011impl<T: ConstantStr> TypeVarName for T {
1012 #[inline]
1013 fn symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target> {
1014 Self::STR.to_symbol(target)
1015 }
1016}
1017
1018pub struct TypeVarConstructor<
1020 N: TypeVarName,
1021 U: ConstructType = AnyType,
1022 L: ConstructType = BottomType,
1023> {
1024 _name: PhantomData<N>,
1025 _upper: PhantomData<U>,
1026 _lower: PhantomData<L>,
1027}
1028
1029impl<N: TypeVarName, U: ConstructType, L: ConstructType> TypeVarConstructor<N, U, L> {
1030 fn new<'target, Tgt>(target: Tgt, env: &TypeVarEnv) -> TypeVarData<'target, Tgt>
1031 where
1032 Tgt: Target<'target>,
1033 {
1034 target.with_local_scope::<_, 2>(|target, mut frame| {
1035 let upper_bound = U::construct_type_with_env(&mut frame, env);
1036 let lower_bound = L::construct_type_with_env(&mut frame, env);
1037 unsafe {
1038 TypeVar::new_unchecked(
1039 &target,
1040 N::symbol(&target),
1041 Some(lower_bound),
1042 Some(upper_bound),
1043 )
1044 .root(target)
1045 }
1046 })
1047 }
1048}
1049
1050unsafe impl<N: TypeVarName, U: ConstructType, L: ConstructType> ConstructType
1051 for TypeVarConstructor<N, U, L>
1052{
1053 type Static = TypeVarConstructor<N, U::Static, L::Static>;
1054
1055 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
1056 where
1057 Tgt: Target<'target>,
1058 {
1059 target.with_local_scope::<_, 2>(|target, mut frame| {
1060 let upper_bound = U::construct_type(&mut frame);
1061 let lower_bound = L::construct_type(&mut frame);
1062 unsafe {
1063 TypeVar::new_unchecked(
1064 &target,
1065 N::symbol(&target),
1066 Some(lower_bound),
1067 Some(upper_bound),
1068 )
1069 .as_value()
1070 .root(target)
1071 }
1072 })
1073 }
1074
1075 #[inline]
1076 fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
1077 where
1078 Tgt: Target<'target>,
1079 {
1080 Some(DataType::tvar_type(target).as_value())
1081 }
1082
1083 fn construct_type_with_env_uncached<'target, Tgt>(
1084 target: Tgt,
1085 env: &TypeVarEnv,
1086 ) -> ValueData<'target, 'static, Tgt>
1087 where
1088 Tgt: Target<'target>,
1089 {
1090 let sym = N::symbol(&target);
1091 env.get(sym).unwrap().as_value().root(target)
1092 }
1093}
1094
1095pub struct ArrayTypeConstructor<T: ConstructType, N: ConstructType> {
1097 _type: PhantomData<T>,
1098 _rank: PhantomData<N>,
1099}
1100
1101unsafe impl<T: ConstructType, N: ConstructType> ConstructType for ArrayTypeConstructor<T, N> {
1102 type Static = ArrayTypeConstructor<T::Static, N::Static>;
1103
1104 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
1105 where
1106 Tgt: Target<'target>,
1107 {
1108 unsafe {
1109 target.with_local_scope::<_, 3>(|target, mut frame| {
1110 let ty_param = T::construct_type(&mut frame);
1111 let rank_param = N::construct_type(&mut frame);
1112 if rank_param.is::<isize>() {
1113 if rank_param.unbox_unchecked::<isize>() < 0 {
1114 panic!("ArrayTypeConstructor rank must be a TypeVar or non-negative ConstantIsize, got {rank_param:?}")
1115 }
1116 }
1117 let params = [ty_param, rank_param];
1118 Self::base_type(&frame)
1119 .unwrap_unchecked()
1120 .apply_type_unchecked(&mut frame, params)
1121 .cast_unchecked::<DataType>()
1122 .rewrap(target)
1123 })
1124 }
1125 }
1126
1127 #[inline]
1128 fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
1129 where
1130 Tgt: Target<'target>,
1131 {
1132 let wrapper = UnionAll::array_type(target).as_value();
1133 Some(wrapper)
1134 }
1135
1136 fn construct_type_with_env_uncached<'target, Tgt>(
1137 target: Tgt,
1138 env: &TypeVarEnv,
1139 ) -> ValueData<'target, 'static, Tgt>
1140 where
1141 Tgt: Target<'target>,
1142 {
1143 unsafe {
1144 target.with_local_scope::<_, 3>(|target, mut frame| {
1145 let ty_param = T::construct_type_with_env(&mut frame, env);
1146 let rank_param = N::construct_type_with_env(&mut frame, env);
1147 if rank_param.is::<isize>() {
1148 if rank_param.unbox_unchecked::<isize>() < 0 {
1149 panic!("ArrayTypeConstructor rank must be a TypeVar or non-negative ConstantIsize, got {rank_param:?}")
1150 }
1151 }
1152 let params = [ty_param, rank_param];
1153 Self::base_type(&frame)
1154 .unwrap_unchecked()
1155 .apply_type_unchecked(&mut frame, params)
1156 .cast_unchecked::<DataType>()
1157 .wrap_with_env(target, env)
1158 })
1159 }
1160 }
1161}
1162
1163pub type RankedArrayType<T, const N: isize> = ArrayTypeConstructor<T, ConstantIsize<N>>;
1164
1165#[macro_export]
1167macro_rules! UnionOf {
1168 [$l:ty, $r:ty] => {
1169 $crate::data::types::construct_type::UnionTypeConstructor<$l, $r>
1170 };
1171 [$l:ty, $($rest:ty),+] => {
1172 $crate::UnionOf![$l, $crate::UnionOf![$($rest),+]]
1173 };
1174}
1175
1176pub struct UnionTypeConstructor<L: ConstructType, R: ConstructType> {
1179 _l: PhantomData<L>,
1180 _r: PhantomData<R>,
1181}
1182
1183unsafe impl<L: ConstructType, R: ConstructType> ConstructType for UnionTypeConstructor<L, R> {
1184 type Static = UnionTypeConstructor<L::Static, R::Static>;
1185
1186 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
1187 where
1188 Tgt: Target<'target>,
1189 {
1190 target.with_local_scope::<_, 2>(|target, mut frame| {
1191 let l = L::construct_type(&mut frame);
1192 let r = R::construct_type(&mut frame);
1193
1194 unsafe { Union::new_unchecked(target, [l, r]) }
1195 })
1196 }
1197
1198 #[inline]
1199 fn base_type<'target, Tgt>(_target: &Tgt) -> Option<Value<'target, 'static>>
1200 where
1201 Tgt: Target<'target>,
1202 {
1203 unsafe {
1204 let ptr = NonNull::new_unchecked(jl_uniontype_type.cast::<jl_value_t>());
1205 Some(
1206 <Value as crate::data::managed::private::ManagedPriv>::wrap_non_null(
1207 ptr,
1208 crate::private::Private,
1209 ),
1210 )
1211 }
1212 }
1213
1214 fn construct_type_with_env_uncached<'target, Tgt>(
1215 target: Tgt,
1216 env: &TypeVarEnv,
1217 ) -> ValueData<'target, 'static, Tgt>
1218 where
1219 Tgt: Target<'target>,
1220 {
1221 target.with_local_scope::<_, 2>(|target, mut frame| {
1222 let l = L::construct_type_with_env(&mut frame, env);
1223 let r = R::construct_type_with_env(&mut frame, env);
1224
1225 unsafe { Union::new_unchecked(target, [l, r]) }
1226 })
1227 }
1228}
1229
1230pub trait BitsUnionCtor: BitsUnionCtorVariant {
1232 fn n_unique_variants() -> usize {
1234 Self::get_variants().len()
1235 }
1236
1237 fn get_variants() -> FxHashSet<TypeId>;
1239}
1240
1241pub trait BitsUnionCtorVariant: ConstructType {
1243 const N: usize;
1244 #[doc(hidden)]
1245 fn add_variants(ids: &mut FxHashSet<TypeId>);
1246}
1247
1248impl<'scope, 'data, T> BitsUnionCtorVariant for T
1249where
1250 T: ConstructType + HasLayout<'scope, 'data>,
1251 T::Layout: IsBits,
1252{
1253 const N: usize = 1;
1254 fn add_variants(ids: &mut FxHashSet<TypeId>) {
1255 ids.insert(Self::type_id());
1256 }
1257}
1258
1259impl<L: BitsUnionCtorVariant, R: BitsUnionCtorVariant> BitsUnionCtorVariant
1260 for UnionTypeConstructor<L, R>
1261{
1262 const N: usize = L::N + R::N;
1263 fn add_variants(ids: &mut FxHashSet<TypeId>) {
1264 L::add_variants(ids);
1265 R::add_variants(ids);
1266 }
1267}
1268
1269impl<L: BitsUnionCtorVariant, R: BitsUnionCtorVariant> BitsUnionCtor
1270 for UnionTypeConstructor<L, R>
1271{
1272 fn get_variants() -> FxHashSet<TypeId> {
1273 let mut set = FxHashSet::<TypeId>::default();
1274
1275 L::add_variants(&mut set);
1276 R::add_variants(&mut set);
1277
1278 set
1279 }
1280}
1281
1282pub struct BottomType;
1283
1284unsafe impl ConstructType for BottomType {
1285 type Static = BottomType;
1286
1287 #[inline]
1288 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
1289 where
1290 Tgt: Target<'target>,
1291 {
1292 unsafe {
1293 let ptr = NonNull::new_unchecked(jl_bottom_type.cast::<jl_value_t>());
1294 target.data_from_ptr(ptr, Private)
1295 }
1296 }
1297
1298 #[inline]
1299 fn base_type<'target, Tgt>(_target: &Tgt) -> Option<Value<'target, 'static>>
1300 where
1301 Tgt: Target<'target>,
1302 {
1303 unsafe {
1304 let ptr = NonNull::new_unchecked(jl_bottom_type.cast::<jl_value_t>());
1305 Some(
1306 <Value as crate::data::managed::private::ManagedPriv>::wrap_non_null(
1307 ptr,
1308 crate::private::Private,
1309 ),
1310 )
1311 }
1312 }
1313
1314 #[inline]
1315 fn construct_type_with_env_uncached<'target, Tgt>(
1316 target: Tgt,
1317 _env: &TypeVarEnv,
1318 ) -> ValueData<'target, 'static, Tgt>
1319 where
1320 Tgt: Target<'target>,
1321 {
1322 unsafe {
1323 let ptr = NonNull::new_unchecked(jl_bottom_type.cast::<jl_value_t>());
1324 target.data_from_ptr(ptr, Private)
1325 }
1326 }
1327}
1328
1329impl_construct_julia_type_primitive!(u8, jl_uint8_type);
1330impl_construct_julia_type_primitive!(u16, jl_uint16_type);
1331impl_construct_julia_type_primitive!(u32, jl_uint32_type);
1332impl_construct_julia_type_primitive!(u64, jl_uint64_type);
1333
1334#[cfg(target_pointer_width = "64")]
1335impl_construct_julia_type_primitive!(usize, jl_uint64_type);
1336#[cfg(target_pointer_width = "32")]
1337impl_construct_julia_type_primitive!(usize, jl_uint32_type);
1338
1339impl_construct_julia_type_primitive!(i8, jl_int8_type);
1340impl_construct_julia_type_primitive!(i16, jl_int16_type);
1341impl_construct_julia_type_primitive!(i32, jl_int32_type);
1342impl_construct_julia_type_primitive!(i64, jl_int64_type);
1343
1344#[cfg(target_pointer_width = "64")]
1345impl_construct_julia_type_primitive!(isize, jl_int64_type);
1346#[cfg(target_pointer_width = "32")]
1347impl_construct_julia_type_primitive!(isize, jl_int32_type);
1348
1349impl_construct_julia_type_primitive!(f32, jl_float32_type);
1350impl_construct_julia_type_primitive!(f64, jl_float64_type);
1351
1352impl_construct_julia_type_primitive!(bool, jl_bool_type);
1353impl_construct_julia_type_primitive!(char, jl_char_type);
1354
1355impl_construct_julia_type_primitive!(*mut c_void, jl_voidpointer_type);
1356
1357unsafe impl<U: ConstructType> ConstructType for *mut U {
1358 type Static = *mut U::Static;
1359
1360 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
1361 where
1362 Tgt: Target<'target>,
1363 {
1364 target.with_local_scope::<_, 1>(|target, mut frame| {
1365 let ty = U::construct_type(&mut frame);
1366 unsafe {
1367 UnionAll::pointer_type(&frame)
1368 .as_value()
1369 .apply_type_unchecked(target, [ty])
1370 }
1371 })
1372 }
1373
1374 #[inline]
1375 fn base_type<'target, Tgt>(_target: &Tgt) -> Option<Value<'target, 'static>>
1376 where
1377 Tgt: Target<'target>,
1378 {
1379 unsafe {
1380 let ptr = NonNull::new_unchecked(jl_pointer_type.cast::<jl_value_t>());
1381 Some(
1382 <Value as crate::data::managed::private::ManagedPriv>::wrap_non_null(
1383 ptr,
1384 crate::private::Private,
1385 ),
1386 )
1387 }
1388 }
1389
1390 fn construct_type_with_env_uncached<'target, Tgt>(
1391 target: Tgt,
1392 env: &TypeVarEnv,
1393 ) -> ValueData<'target, 'static, Tgt>
1394 where
1395 Tgt: Target<'target>,
1396 {
1397 target.with_local_scope::<_, 1>(|target, mut frame| {
1398 let ty = U::construct_type_with_env(&mut frame, env);
1399 unsafe {
1400 UnionAll::pointer_type(&frame)
1401 .as_value()
1402 .apply_type_unchecked(target, [ty])
1403 }
1404 })
1405 }
1406}
1407
1408struct ConstructedTypes {
1409 data: Cache<FnvHashMap<TypeId, ValueUnbound>>,
1410}
1411
1412impl ConstructedTypes {
1413 const fn new() -> Self {
1414 let hasher = fnv::FnvBuildHasher::new();
1415 let map = std::collections::HashMap::with_hasher(hasher);
1416 let cache = Cache::new(map);
1417
1418 ConstructedTypes { data: cache }
1419 }
1420
1421 #[inline]
1422 fn find_or_construct<T: ConstructType>(&self) -> WeakValue<'static, 'static> {
1423 let tid = T::type_id();
1424 let res = unsafe {
1425 self.data.read(
1426 #[inline]
1427 |cache| {
1428 if let Some(res) = cache.cache().get(&tid).copied() {
1429 return Some(res.as_weak());
1430 }
1431
1432 None
1433 },
1434 )
1435 };
1436
1437 if let Some(res) = res {
1438 return res;
1439 }
1440
1441 do_construct::<T>(self, tid)
1442 }
1443
1444 #[inline]
1445 fn find_or_construct_with_env<T: ConstructType>(
1446 &self,
1447 env: &TypeVarEnv,
1448 ) -> WeakValue<'static, 'static> {
1449 let tid = T::type_id();
1450 let res = unsafe {
1451 self.data.read(
1452 #[inline]
1453 |cache| {
1454 if let Some(res) = cache.cache().get(&tid).copied() {
1455 return Some(res.as_weak());
1456 }
1457
1458 None
1459 },
1460 )
1461 };
1462
1463 if let Some(res) = res {
1464 return res;
1465 }
1466
1467 do_construct_with_context::<T>(self, tid, env)
1468 }
1469}
1470
1471#[cold]
1473fn do_construct<T: ConstructType>(
1474 ct: &ConstructedTypes,
1475 tid: TypeId,
1476) -> WeakValue<'static, 'static> {
1477 unsafe {
1478 let unrooted = Unrooted::new();
1479 unrooted.with_local_scope::<_, 1>(|target, mut frame| {
1480 let ty = T::construct_type_uncached(&mut frame);
1481
1482 if ty.is::<DataType>() {
1483 let dt = ty.cast_unchecked::<DataType>();
1484 if !dt.has_free_type_vars() && (!dt.is::<Tuple>() || dt.is_concrete_type()) {
1485 ct.data.write(
1486 #[inline]
1487 |cache| {
1488 cache.cache_mut().insert(tid, ty.leak().as_value());
1489 cache.roots_mut().insert(ty.as_value());
1490 },
1491 );
1492 }
1493 } else if ty.is::<u8>() || ty.is::<i8>() {
1494 ct.data.write(|cache| {
1495 cache.cache_mut().insert(tid, ty.leak().as_value());
1496 cache.roots_mut().insert(ty.as_value());
1497 });
1498 }
1499
1500 ty.root(target)
1501 })
1502 }
1503}
1504
1505#[cold]
1507fn do_construct_with_context<T: ConstructType>(
1508 ct: &ConstructedTypes,
1509 tid: TypeId,
1510 env: &TypeVarEnv,
1511) -> WeakValue<'static, 'static> {
1512 unsafe {
1513 let unrooted = Unrooted::new();
1514 unrooted.with_local_scope::<_, 1>(|target, mut frame| {
1515 let ty = T::construct_type_with_env_uncached(&mut frame, env);
1516
1517 if ty.is::<DataType>() {
1518 let dt = ty.cast_unchecked::<DataType>();
1519 if !dt.has_free_type_vars() && (!dt.is::<Tuple>() || dt.is_concrete_type()) {
1520 ct.data.write(
1521 #[inline]
1522 |cache| {
1523 cache.cache_mut().insert(tid, ty.leak().as_value());
1524 cache.roots_mut().insert(ty.as_value());
1525 },
1526 );
1527 }
1528 } else if ty.is::<u8>() || ty.is::<i8>() {
1529 ct.data.write(
1530 #[inline]
1531 |cache| {
1532 cache.cache_mut().insert(tid, ty.leak().as_value());
1533 cache.roots_mut().insert(ty.as_value());
1534 },
1535 );
1536 }
1537
1538 ty.root(target)
1539 })
1540 }
1541}