1use std::{
20 fmt::Debug,
21 marker::PhantomData,
22 ops::{Deref, DerefMut},
23 ptr::NonNull,
24};
25
26use jl_sys::jl_value_t;
27
28use super::{
29 Value, ValueData, WeakValue,
30 tracked::{Tracked, TrackedMut},
31};
32use crate::{
33 convert::{
34 ccall_types::{CCallArg, CCallReturn},
35 into_julia::IntoJulia,
36 },
37 data::{
38 layout::valid_layout::{ValidField, ValidLayout},
39 managed::{Managed, Weak, datatype::DataType, private::ManagedPriv},
40 types::{
41 abstract_type::AnyType,
42 construct_type::{ArrayTypeConstructor, ConstantIsize, ConstructType},
43 typecheck::Typecheck,
44 },
45 },
46 error::{JlrsResult, TypeError},
47 memory::{
48 scope::LocalScope,
49 target::{Target, TargetResult},
50 },
51 prelude::{TypedArray, TypedRankedArray},
52 private::Private,
53};
54
55pub trait AsTyped<'scope, 'data>: Managed<'scope, 'data> {
57 fn as_typed(self) -> JlrsResult<TypedValue<'scope, 'data, Self>>;
58}
59
60#[repr(transparent)]
62pub struct TypedValue<'scope, 'data, T>(
63 NonNull<jl_value_t>,
64 PhantomData<T>,
65 PhantomData<&'scope ()>,
66 PhantomData<&'data ()>,
67);
68
69impl<U: ConstructType + IntoJulia> TypedValue<'_, '_, U> {
70 #[inline]
73 pub fn new<'target, Tgt>(target: Tgt, data: U) -> TypedValueData<'target, 'static, U, Tgt>
74 where
75 Tgt: Target<'target>,
76 {
77 unsafe {
78 Value::new(&target, data)
79 .as_value()
80 .cast_unchecked::<TypedValue<U>>()
81 .root(target)
82 }
83 }
84}
85
86impl<U: ConstructType> TypedValue<'_, '_, U> {
87 #[inline]
90 pub fn try_new_with<'target, L, Tgt>(
91 target: Tgt,
92 data: L,
93 ) -> JlrsResult<TypedValueData<'target, 'static, U, Tgt>>
94 where
95 L: ValidLayout,
96 Tgt: Target<'target>,
97 {
98 unsafe {
99 let v = Value::try_new_with::<U, _, _>(&target, data)?.as_value();
100 Ok(TypedValue::<U>::from_value_unchecked(v).root(target))
101 }
102 }
103}
104
105impl<'scope, 'data, U: ConstructType> TypedValue<'scope, 'data, U> {
106 pub fn from_value<'target, Tgt>(
108 target: &Tgt,
109 value: Value<'scope, 'data>,
110 ) -> JlrsResult<TypedValue<'scope, 'data, U>>
111 where
112 Tgt: Target<'target>,
113 {
114 unsafe {
115 target.local_scope::<_, 1>(|mut frame| {
116 let ty = U::construct_type(&mut frame).as_value();
117 if value.isa(ty) {
118 Ok(TypedValue::<U>::wrap_non_null(
119 value.unwrap_non_null(Private),
120 Private,
121 ))
122 } else {
123 Err(TypeError::NotA {
124 value: value.display_string_or("<Cannot display value>"),
125 field_type: ty.display_string_or("<Cannot display type>"),
126 })?
127 }
128 })
129 }
130 }
131
132 #[inline]
137 pub unsafe fn from_value_unchecked(
138 value: Value<'scope, 'data>,
139 ) -> TypedValue<'scope, 'data, U> {
140 unsafe { TypedValue::<U>::wrap_non_null(value.unwrap_non_null(Private), Private) }
141 }
142}
143
144impl<'scope, 'data, U: ValidLayout + ConstructType> TypedValue<'scope, 'data, U> {
145 #[inline]
149 pub unsafe fn track_shared<'tracked>(
150 &'tracked self,
151 ) -> JlrsResult<Tracked<'tracked, 'scope, 'data, U>> {
152 self.deref().track_shared()
153 }
154
155 #[inline]
159 pub unsafe fn track_exclusive<'tracked>(
160 &'tracked mut self,
161 ) -> JlrsResult<TrackedMut<'tracked, 'scope, 'data, U>> {
162 unsafe { self.deref_mut().track_exclusive() }
163 }
164}
165
166impl<'scope, 'data, U: ConstructType> TypedValue<'scope, 'data, U> {
167 #[inline]
171 pub unsafe fn track_shared_as<'tracked, V: ValidLayout>(
172 &'tracked self,
173 ) -> JlrsResult<Tracked<'tracked, 'scope, 'data, V>> {
174 self.deref().track_shared()
175 }
176
177 #[inline]
181 pub unsafe fn track_exclusive_as<'tracked, V: ValidLayout>(
182 &'tracked mut self,
183 ) -> JlrsResult<TrackedMut<'tracked, 'scope, 'data, V>> {
184 unsafe { self.deref_mut().track_exclusive() }
185 }
186}
187
188impl<'scope, 'data, T: ConstructType, const N: isize>
189 TypedValue<'scope, 'data, ArrayTypeConstructor<T, ConstantIsize<N>>>
190{
191 #[inline]
193 pub fn as_typed_ranked_array(self) -> TypedRankedArray<'scope, 'data, T, N> {
194 unsafe { std::mem::transmute(self) }
195 }
196}
197
198impl<'scope, 'data, T: ConstructType, N: ConstructType>
199 TypedValue<'scope, 'data, ArrayTypeConstructor<T, N>>
200{
201 #[inline]
203 pub fn as_typed_array(self) -> TypedArray<'scope, 'data, T> {
204 unsafe { std::mem::transmute(self) }
205 }
206}
207
208impl<U: ConstructType + ValidLayout + Send> TypedValueUnbound<U> {
209 #[inline]
213 pub unsafe fn track_shared_unbound(self) -> JlrsResult<Tracked<'static, 'static, 'static, U>> {
214 unsafe { self.as_value().track_shared_unbound() }
215 }
216
217 #[inline]
221 pub unsafe fn track_exclusive_unbound(
222 self,
223 ) -> JlrsResult<TrackedMut<'static, 'static, 'static, U>> {
224 unsafe { self.as_value().track_exclusive_unbound() }
225 }
226}
227
228impl<U: ConstructType> TypedValueUnbound<U> {
229 #[inline]
233 pub unsafe fn track_shared_unbound_as<V: ValidLayout + Send>(
234 self,
235 ) -> JlrsResult<Tracked<'static, 'static, 'static, V>> {
236 unsafe { self.as_value().track_shared_unbound() }
237 }
238
239 #[inline]
243 pub unsafe fn track_exclusive_unbound_as<V: ValidLayout + Send>(
244 self,
245 ) -> JlrsResult<TrackedMut<'static, 'static, 'static, V>> {
246 unsafe { self.as_value().track_exclusive_unbound() }
247 }
248}
249
250impl<'scope, 'data, U: ConstructType> Deref for TypedValue<'scope, 'data, U> {
251 type Target = Value<'scope, 'data>;
252
253 #[inline]
254 fn deref(&self) -> &Self::Target {
255 unsafe { std::mem::transmute(self) }
256 }
257}
258impl<'scope, 'data, U: ConstructType> DerefMut for TypedValue<'scope, 'data, U> {
259 #[inline]
260 fn deref_mut(&mut self) -> &mut Self::Target {
261 unsafe { std::mem::transmute(self) }
262 }
263}
264
265impl<T> Debug for TypedValue<'_, '_, T>
266where
267 T: ConstructType,
268{
269 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 write!(fmt, "{:?}", self.as_value())
271 }
272}
273
274impl<T> Clone for TypedValue<'_, '_, T>
275where
276 T: ConstructType,
277{
278 #[inline]
279 fn clone(&self) -> Self {
280 unsafe { Self::wrap_non_null(self.unwrap_non_null(Private), Private) }
281 }
282}
283
284impl<T> Copy for TypedValue<'_, '_, T> where T: ConstructType {}
285
286unsafe impl<T> ValidLayout for TypedValue<'_, '_, T>
287where
288 T: ConstructType,
289{
290 #[inline]
291 fn valid_layout(v: Value) -> bool {
292 WeakValue::valid_layout(v)
293 }
294
295 #[inline]
296 fn type_object<'target, Tgt>(target: &Tgt) -> Value<'target, 'static>
297 where
298 Tgt: Target<'target>,
299 {
300 T::base_type(target).expect("Type has no base type")
301 }
302
303 const IS_REF: bool = true;
304}
305unsafe impl<T> ValidField for Option<TypedValue<'_, '_, T>>
306where
307 T: ConstructType,
308{
309 #[inline]
310 fn valid_field(v: Value) -> bool {
311 Option::<WeakValue>::valid_field(v)
312 }
313}
314
315impl<'scope, 'data, T> ManagedPriv<'scope, 'data> for TypedValue<'scope, 'data, T>
316where
317 T: ConstructType,
318{
319 type Wraps = jl_value_t;
320 type WithLifetimes<'target, 'da> = TypedValue<'target, 'da, T>;
321 const NAME: &'static str = "TypedValue";
322
323 #[inline]
326 unsafe fn wrap_non_null(inner: NonNull<Self::Wraps>, _: Private) -> Self {
327 Self(inner, PhantomData, PhantomData, PhantomData)
328 }
329
330 #[inline]
331 fn unwrap_non_null(self, _: Private) -> NonNull<Self::Wraps> {
332 self.0
333 }
334}
335
336unsafe impl<'scope, 'data, T> Typecheck for TypedValue<'scope, 'data, T>
337where
338 T: ValidLayout + ConstructType,
339{
340 #[inline]
341 fn typecheck(t: DataType) -> bool {
342 T::valid_layout(t.as_value())
343 }
344}
345
346unsafe impl<U> ConstructType for TypedValue<'_, '_, U>
347where
348 U: ConstructType,
349{
350 type Static = U::Static;
351
352 #[inline]
353 fn construct_type_uncached<'target, Tgt>(target: Tgt) -> ValueData<'target, 'static, Tgt>
354 where
355 Tgt: Target<'target>,
356 {
357 U::construct_type_uncached(target)
358 }
359
360 #[inline]
361 fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
362 where
363 Tgt: Target<'target>,
364 {
365 U::base_type(target)
366 }
367
368 fn construct_type_with_env_uncached<'target, Tgt>(
369 target: Tgt,
370 env: &crate::data::types::construct_type::TypeVarEnv,
371 ) -> ValueData<'target, 'static, Tgt>
372 where
373 Tgt: Target<'target>,
374 {
375 U::construct_type_with_env_uncached(target, env)
376 }
377}
378
379use crate::memory::target::TargetType;
380
381pub type WeakTypedValue<'scope, 'data, T> = Weak<'scope, 'data, TypedValue<'scope, 'data, T>>;
382
383impl<'scope, 'data> WeakTypedValue<'scope, 'data, AnyType> {
384 #[inline]
385 pub fn from_value_ref(value_ref: WeakValue<'scope, 'data>) -> Self {
386 WeakTypedValue::wrap(value_ref.ptr())
387 }
388}
389
390pub type TypedValueRet<T> = Weak<'static, 'static, TypedValue<'static, 'static, T>>;
393
394pub type TypedValueData<'target, 'data, U, Tgt> =
396 <Tgt as TargetType<'target>>::Data<'data, TypedValue<'target, 'data, U>>;
397
398pub type TypedValueResult<'target, 'data, U, T> =
401 TargetResult<'target, 'data, TypedValue<'target, 'data, U>, T>;
402
403pub type TypedValueUnbound<T> = TypedValue<'static, 'static, T>;
404
405unsafe impl<'scope, 'data, T: ConstructType> CCallArg for TypedValue<'scope, 'data, T> {
406 type CCallArgType = Value<'scope, 'data>;
407 type FunctionArgType = T;
408}
409
410unsafe impl<T: ConstructType> CCallReturn for WeakTypedValue<'static, 'static, T> {
411 type CCallReturnType = Value<'static, 'static>;
412 type FunctionReturnType = T;
413 type ReturnAs = Self;
414
415 #[inline]
416 unsafe fn return_or_throw(self) -> Self::ReturnAs {
417 self
418 }
419}