Skip to main content

packr_abi/
value.rs

1//! Runtime values
2
3use alloc::boxed::Box;
4use alloc::collections::{BTreeMap, BTreeSet};
5use alloc::string::String;
6use alloc::vec::Vec;
7
8/// Runtime type representation for CGRF v2
9#[derive(Debug, Clone, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub enum ValueType {
12    Bool,
13    U8,
14    U16,
15    U32,
16    U64,
17    S8,
18    S16,
19    S32,
20    S64,
21    F32,
22    F64,
23    Char,
24    String,
25    List(Box<ValueType>),
26    Option(Box<ValueType>),
27    Result {
28        ok: Box<ValueType>,
29        err: Box<ValueType>,
30    },
31    Record(String),  // type name
32    Variant(String), // type name
33    Tuple(Vec<ValueType>),
34    Flags,
35}
36
37/// A runtime value that can be passed across package boundaries
38#[derive(Debug, Clone, PartialEq)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40pub enum Value {
41    // Primitives
42    Bool(bool),
43    U8(u8),
44    U16(u16),
45    U32(u32),
46    U64(u64),
47    S8(i8),
48    S16(i16),
49    S32(i32),
50    S64(i64),
51    F32(f32),
52    F64(f64),
53    Char(char),
54    String(String),
55
56    // Compound types WITH type info
57    List {
58        elem_type: ValueType,
59        items: Vec<Value>,
60    },
61    Option {
62        inner_type: ValueType,
63        value: Option<Box<Value>>,
64    },
65    Result {
66        ok_type: ValueType,
67        err_type: ValueType,
68        value: core::result::Result<Box<Value>, Box<Value>>,
69    },
70    Record {
71        type_name: String,
72        fields: Vec<(String, Value)>,
73    },
74    Variant {
75        type_name: String,
76        case_name: String,
77        tag: usize,
78        payload: Vec<Value>,
79    },
80
81    // Keep Tuple as-is (no type info needed - positional)
82    Tuple(Vec<Value>),
83    Flags(u64),
84}
85
86impl Value {
87    /// Helper to create a symbol (variant tag 0 with string payload)
88    pub fn sym(s: impl Into<String>) -> Self {
89        Value::Variant {
90            type_name: String::from("expr"),
91            case_name: String::from("sym"),
92            tag: 0,
93            payload: alloc::vec![Value::String(s.into())],
94        }
95    }
96
97    /// Helper to create a number (variant tag 1 with s64 payload)
98    pub fn num(n: i64) -> Self {
99        Value::Variant {
100            type_name: String::from("expr"),
101            case_name: String::from("num"),
102            tag: 1,
103            payload: alloc::vec![Value::S64(n)],
104        }
105    }
106
107    /// Helper to create a list (variant tag 4 with list payload)
108    pub fn lst(items: Vec<Value>) -> Self {
109        Value::Variant {
110            type_name: String::from("expr"),
111            case_name: String::from("lst"),
112            tag: 4,
113            payload: alloc::vec![Value::List {
114                elem_type: ValueType::Variant(String::from("expr")),
115                items,
116            }],
117        }
118    }
119
120    /// Infer the ValueType from this Value
121    pub fn infer_type(&self) -> ValueType {
122        match self {
123            Value::Bool(_) => ValueType::Bool,
124            Value::U8(_) => ValueType::U8,
125            Value::U16(_) => ValueType::U16,
126            Value::U32(_) => ValueType::U32,
127            Value::U64(_) => ValueType::U64,
128            Value::S8(_) => ValueType::S8,
129            Value::S16(_) => ValueType::S16,
130            Value::S32(_) => ValueType::S32,
131            Value::S64(_) => ValueType::S64,
132            Value::F32(_) => ValueType::F32,
133            Value::F64(_) => ValueType::F64,
134            Value::Char(_) => ValueType::Char,
135            Value::String(_) => ValueType::String,
136            Value::List { elem_type, .. } => ValueType::List(Box::new(elem_type.clone())),
137            Value::Option { inner_type, .. } => ValueType::Option(Box::new(inner_type.clone())),
138            Value::Result {
139                ok_type, err_type, ..
140            } => ValueType::Result {
141                ok: Box::new(ok_type.clone()),
142                err: Box::new(err_type.clone()),
143            },
144            Value::Record { type_name, .. } => ValueType::Record(type_name.clone()),
145            Value::Variant { type_name, .. } => ValueType::Variant(type_name.clone()),
146            Value::Tuple(items) => ValueType::Tuple(items.iter().map(|v| v.infer_type()).collect()),
147            Value::Flags(_) => ValueType::Flags,
148        }
149    }
150}
151
152// ============================================================================
153// From implementations for primitives
154// ============================================================================
155
156impl From<bool> for Value {
157    fn from(v: bool) -> Self {
158        Value::Bool(v)
159    }
160}
161
162impl From<u8> for Value {
163    fn from(v: u8) -> Self {
164        Value::U8(v)
165    }
166}
167
168impl From<u16> for Value {
169    fn from(v: u16) -> Self {
170        Value::U16(v)
171    }
172}
173
174impl From<u32> for Value {
175    fn from(v: u32) -> Self {
176        Value::U32(v)
177    }
178}
179
180impl From<u64> for Value {
181    fn from(v: u64) -> Self {
182        Value::U64(v)
183    }
184}
185
186impl From<i8> for Value {
187    fn from(v: i8) -> Self {
188        Value::S8(v)
189    }
190}
191
192impl From<i16> for Value {
193    fn from(v: i16) -> Self {
194        Value::S16(v)
195    }
196}
197
198impl From<i32> for Value {
199    fn from(v: i32) -> Self {
200        Value::S32(v)
201    }
202}
203
204impl From<i64> for Value {
205    fn from(v: i64) -> Self {
206        Value::S64(v)
207    }
208}
209
210impl From<f32> for Value {
211    fn from(v: f32) -> Self {
212        Value::F32(v)
213    }
214}
215
216impl From<f64> for Value {
217    fn from(v: f64) -> Self {
218        Value::F64(v)
219    }
220}
221
222impl From<char> for Value {
223    fn from(v: char) -> Self {
224        Value::Char(v)
225    }
226}
227
228impl From<String> for Value {
229    fn from(v: String) -> Self {
230        Value::String(v)
231    }
232}
233
234impl From<&str> for Value {
235    fn from(v: &str) -> Self {
236        Value::String(String::from(v))
237    }
238}
239
240impl<T: Into<Value>> From<Vec<T>> for Value {
241    fn from(v: Vec<T>) -> Self {
242        let items: Vec<Value> = v.into_iter().map(Into::into).collect();
243        // Infer elem_type from first item, default to S32
244        let elem_type = items
245            .first()
246            .map(|v| v.infer_type())
247            .unwrap_or(ValueType::S32);
248        Value::List { elem_type, items }
249    }
250}
251
252impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
253    fn from(v: [T; N]) -> Self {
254        let items: Vec<Value> = v.into_iter().map(Into::into).collect();
255        let elem_type = items
256            .first()
257            .map(|v| v.infer_type())
258            .unwrap_or(ValueType::S32);
259        Value::List { elem_type, items }
260    }
261}
262
263impl<T: TryFrom<Value, Error = ConversionError>, const N: usize> TryFrom<Value> for [T; N] {
264    type Error = ConversionError;
265    fn try_from(v: Value) -> Result<Self, Self::Error> {
266        match v {
267            Value::List { items, .. } => {
268                if items.len() != N {
269                    return Err(ConversionError::WrongFieldCount {
270                        expected: N,
271                        got: items.len(),
272                    });
273                }
274                let vec: Vec<T> = items
275                    .into_iter()
276                    .enumerate()
277                    .map(|(i, item)| {
278                        T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
279                    })
280                    .collect::<Result<Vec<T>, _>>()?;
281                vec.try_into().map_err(|_| {
282                    ConversionError::ExpectedList(String::from("array conversion failed"))
283                })
284            }
285            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
286        }
287    }
288}
289
290impl<T: Into<Value>> From<Option<T>> for Value {
291    fn from(v: Option<T>) -> Self {
292        let (inner_type, value) = match v {
293            Some(x) => {
294                let val: Value = x.into();
295                let ty = val.infer_type();
296                (ty, Some(Box::new(val)))
297            }
298            None => (ValueType::S32, None), // Default type for None
299        };
300        Value::Option { inner_type, value }
301    }
302}
303
304impl<T: Into<Value>> From<Box<T>> for Value {
305    fn from(v: Box<T>) -> Self {
306        (*v).into()
307    }
308}
309
310// ============================================================================
311// TryFrom implementations for primitives
312// ============================================================================
313
314use crate::ConversionError;
315
316impl TryFrom<Value> for bool {
317    type Error = ConversionError;
318    fn try_from(v: Value) -> Result<Self, Self::Error> {
319        match v {
320            Value::Bool(x) => Ok(x),
321            other => Err(ConversionError::TypeMismatch {
322                expected: String::from("bool"),
323                got: format!("{:?}", other),
324            }),
325        }
326    }
327}
328
329impl TryFrom<Value> for u8 {
330    type Error = ConversionError;
331    fn try_from(v: Value) -> Result<Self, Self::Error> {
332        match v {
333            Value::U8(x) => Ok(x),
334            other => Err(ConversionError::TypeMismatch {
335                expected: String::from("u8"),
336                got: format!("{:?}", other),
337            }),
338        }
339    }
340}
341
342impl TryFrom<Value> for u16 {
343    type Error = ConversionError;
344    fn try_from(v: Value) -> Result<Self, Self::Error> {
345        match v {
346            Value::U16(x) => Ok(x),
347            other => Err(ConversionError::TypeMismatch {
348                expected: String::from("u16"),
349                got: format!("{:?}", other),
350            }),
351        }
352    }
353}
354
355impl TryFrom<Value> for u32 {
356    type Error = ConversionError;
357    fn try_from(v: Value) -> Result<Self, Self::Error> {
358        match v {
359            Value::U32(x) => Ok(x),
360            other => Err(ConversionError::TypeMismatch {
361                expected: String::from("u32"),
362                got: format!("{:?}", other),
363            }),
364        }
365    }
366}
367
368impl TryFrom<Value> for u64 {
369    type Error = ConversionError;
370    fn try_from(v: Value) -> Result<Self, Self::Error> {
371        match v {
372            Value::U64(x) => Ok(x),
373            other => Err(ConversionError::TypeMismatch {
374                expected: String::from("u64"),
375                got: format!("{:?}", other),
376            }),
377        }
378    }
379}
380
381impl TryFrom<Value> for i8 {
382    type Error = ConversionError;
383    fn try_from(v: Value) -> Result<Self, Self::Error> {
384        match v {
385            Value::S8(x) => Ok(x),
386            other => Err(ConversionError::TypeMismatch {
387                expected: String::from("i8"),
388                got: format!("{:?}", other),
389            }),
390        }
391    }
392}
393
394impl TryFrom<Value> for i16 {
395    type Error = ConversionError;
396    fn try_from(v: Value) -> Result<Self, Self::Error> {
397        match v {
398            Value::S16(x) => Ok(x),
399            other => Err(ConversionError::TypeMismatch {
400                expected: String::from("i16"),
401                got: format!("{:?}", other),
402            }),
403        }
404    }
405}
406
407impl TryFrom<Value> for i32 {
408    type Error = ConversionError;
409    fn try_from(v: Value) -> Result<Self, Self::Error> {
410        match v {
411            Value::S32(x) => Ok(x),
412            other => Err(ConversionError::TypeMismatch {
413                expected: String::from("i32"),
414                got: format!("{:?}", other),
415            }),
416        }
417    }
418}
419
420impl TryFrom<Value> for i64 {
421    type Error = ConversionError;
422    fn try_from(v: Value) -> Result<Self, Self::Error> {
423        match v {
424            Value::S64(x) => Ok(x),
425            other => Err(ConversionError::TypeMismatch {
426                expected: String::from("i64"),
427                got: format!("{:?}", other),
428            }),
429        }
430    }
431}
432
433impl TryFrom<Value> for f32 {
434    type Error = ConversionError;
435    fn try_from(v: Value) -> Result<Self, Self::Error> {
436        match v {
437            Value::F32(x) => Ok(x),
438            other => Err(ConversionError::TypeMismatch {
439                expected: String::from("f32"),
440                got: format!("{:?}", other),
441            }),
442        }
443    }
444}
445
446impl TryFrom<Value> for f64 {
447    type Error = ConversionError;
448    fn try_from(v: Value) -> Result<Self, Self::Error> {
449        match v {
450            Value::F64(x) => Ok(x),
451            other => Err(ConversionError::TypeMismatch {
452                expected: String::from("f64"),
453                got: format!("{:?}", other),
454            }),
455        }
456    }
457}
458
459impl TryFrom<Value> for char {
460    type Error = ConversionError;
461    fn try_from(v: Value) -> Result<Self, Self::Error> {
462        match v {
463            Value::Char(x) => Ok(x),
464            other => Err(ConversionError::TypeMismatch {
465                expected: String::from("char"),
466                got: format!("{:?}", other),
467            }),
468        }
469    }
470}
471
472impl TryFrom<Value> for String {
473    type Error = ConversionError;
474    fn try_from(v: Value) -> Result<Self, Self::Error> {
475        match v {
476            Value::String(x) => Ok(x),
477            other => Err(ConversionError::TypeMismatch {
478                expected: String::from("String"),
479                got: format!("{:?}", other),
480            }),
481        }
482    }
483}
484
485impl<T: TryFrom<Value, Error = ConversionError>> TryFrom<Value> for Vec<T> {
486    type Error = ConversionError;
487    fn try_from(v: Value) -> Result<Self, Self::Error> {
488        match v {
489            Value::List { items, .. } => items
490                .into_iter()
491                .enumerate()
492                .map(|(i, item)| {
493                    T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
494                })
495                .collect(),
496            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
497        }
498    }
499}
500
501impl<T: Into<Value> + Ord> From<BTreeSet<T>> for Value {
502    fn from(v: BTreeSet<T>) -> Self {
503        let items: Vec<Value> = v.into_iter().map(Into::into).collect();
504        let elem_type = items
505            .first()
506            .map(|v| v.infer_type())
507            .unwrap_or(ValueType::S32);
508        Value::List { elem_type, items }
509    }
510}
511
512impl<T: TryFrom<Value, Error = ConversionError> + Ord> TryFrom<Value> for BTreeSet<T> {
513    type Error = ConversionError;
514    fn try_from(v: Value) -> Result<Self, Self::Error> {
515        match v {
516            Value::List { items, .. } => items
517                .into_iter()
518                .enumerate()
519                .map(|(i, item)| {
520                    T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
521                })
522                .collect(),
523            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
524        }
525    }
526}
527
528impl<K: Into<Value> + Ord, V: Into<Value>> From<BTreeMap<K, V>> for Value {
529    fn from(v: BTreeMap<K, V>) -> Self {
530        let items: Vec<Value> = v
531            .into_iter()
532            .map(|(k, v)| Value::Tuple(Vec::from([k.into(), v.into()])))
533            .collect();
534        let elem_type = items
535            .first()
536            .map(|v| v.infer_type())
537            .unwrap_or(ValueType::S32);
538        Value::List { elem_type, items }
539    }
540}
541
542impl<
543        K: TryFrom<Value, Error = ConversionError> + Ord,
544        V: TryFrom<Value, Error = ConversionError>,
545    > TryFrom<Value> for BTreeMap<K, V>
546{
547    type Error = ConversionError;
548    fn try_from(v: Value) -> Result<Self, Self::Error> {
549        match v {
550            Value::List { items, .. } => items
551                .into_iter()
552                .enumerate()
553                .map(|(i, item)| match item {
554                    Value::Tuple(mut fields) if fields.len() == 2 => {
555                        let v_val = fields.pop().unwrap();
556                        let k_val = fields.pop().unwrap();
557                        let k = K::try_from(k_val)
558                            .map_err(|e| ConversionError::IndexError(i, Box::new(e)))?;
559                        let v = V::try_from(v_val)
560                            .map_err(|e| ConversionError::IndexError(i, Box::new(e)))?;
561                        Ok((k, v))
562                    }
563                    other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
564                })
565                .collect(),
566            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
567        }
568    }
569}
570
571// ============================================================================
572// FromValue trait - avoids coherence issues with TryFrom for Option<T>
573// ============================================================================
574
575/// Trait for converting from a Value.
576///
577/// This trait exists to avoid coherence issues with Rust's blanket
578/// `impl<T, U> TryFrom<U> for T where U: Into<T>` when implementing
579/// conversions for generic types like `Option<T>`.
580pub trait FromValue: Sized {
581    fn from_value(v: Value) -> Result<Self, ConversionError>;
582}
583
584/// Blanket implementation for all types that implement TryFrom<Value>
585impl<T: TryFrom<Value, Error = ConversionError>> FromValue for T {
586    fn from_value(v: Value) -> Result<Self, ConversionError> {
587        T::try_from(v)
588    }
589}
590
591/// FromValue implementation for Value itself (identity conversion)
592impl FromValue for Value {
593    fn from_value(v: Value) -> Result<Self, ConversionError> {
594        Ok(v)
595    }
596}
597
598/// FromValue implementation for Option<T> - uses FromValue bound to avoid coherence issues
599impl<T: FromValue> FromValue for Option<T> {
600    fn from_value(v: Value) -> Result<Self, ConversionError> {
601        match v {
602            Value::Option { value: None, .. } => Ok(None),
603            Value::Option {
604                value: Some(inner), ..
605            } => {
606                let value = T::from_value(*inner)?;
607                Ok(Some(value))
608            }
609            other => Err(ConversionError::ExpectedOption(format!("{:?}", other))),
610        }
611    }
612}
613
614/// FromValue implementation for Result<T, E> - uses FromValue bounds to support nested Option types
615impl<T: FromValue, E: FromValue> FromValue for core::result::Result<T, E> {
616    fn from_value(v: Value) -> Result<Self, ConversionError> {
617        match v {
618            Value::Result {
619                value: Ok(inner), ..
620            } => {
621                let value = T::from_value(*inner)
622                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
623                Ok(Ok(value))
624            }
625            Value::Result {
626                value: Err(inner), ..
627            } => {
628                let value = E::from_value(*inner)
629                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
630                Ok(Err(value))
631            }
632            // Also support legacy variant encoding for backwards compatibility
633            Value::Variant {
634                tag: 0, payload, ..
635            } if !payload.is_empty() => {
636                let value = T::from_value(payload.into_iter().next().unwrap())
637                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
638                Ok(Ok(value))
639            }
640            Value::Variant {
641                tag: 1, payload, ..
642            } if !payload.is_empty() => {
643                let value = E::from_value(payload.into_iter().next().unwrap())
644                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
645                Ok(Err(value))
646            }
647            Value::Variant { tag, .. } => Err(ConversionError::UnknownTag { tag, max: 1 }),
648            other => Err(ConversionError::ExpectedVariant(format!("{:?}", other))),
649        }
650    }
651}
652
653// ============================================================================
654// Tuple conversions (for common sizes)
655// ============================================================================
656
657// Empty tuple / unit
658impl From<()> for Value {
659    fn from(_: ()) -> Self {
660        Value::Tuple(Vec::new())
661    }
662}
663
664impl TryFrom<Value> for () {
665    type Error = ConversionError;
666    fn try_from(v: Value) -> Result<Self, Self::Error> {
667        match v {
668            Value::Tuple(items) if items.is_empty() => Ok(()),
669            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
670        }
671    }
672}
673
674// 1-tuple
675impl<A: Into<Value>> From<(A,)> for Value {
676    fn from((a,): (A,)) -> Self {
677        Value::Tuple(alloc::vec![a.into()])
678    }
679}
680
681impl<A: TryFrom<Value, Error = ConversionError>> TryFrom<Value> for (A,) {
682    type Error = ConversionError;
683    fn try_from(v: Value) -> Result<Self, Self::Error> {
684        match v {
685            Value::Tuple(mut items) if items.len() == 1 => {
686                let a = A::try_from(items.remove(0))
687                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
688                Ok((a,))
689            }
690            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
691        }
692    }
693}
694
695// 2-tuple
696impl<A: Into<Value>, B: Into<Value>> From<(A, B)> for Value {
697    fn from((a, b): (A, B)) -> Self {
698        Value::Tuple(alloc::vec![a.into(), b.into()])
699    }
700}
701
702impl<A: TryFrom<Value, Error = ConversionError>, B: TryFrom<Value, Error = ConversionError>>
703    TryFrom<Value> for (A, B)
704{
705    type Error = ConversionError;
706    fn try_from(v: Value) -> Result<Self, Self::Error> {
707        match v {
708            Value::Tuple(mut items) if items.len() == 2 => {
709                let b = B::try_from(items.remove(1))
710                    .map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
711                let a = A::try_from(items.remove(0))
712                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
713                Ok((a, b))
714            }
715            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
716        }
717    }
718}
719
720// 3-tuple
721impl<A: Into<Value>, B: Into<Value>, C: Into<Value>> From<(A, B, C)> for Value {
722    fn from((a, b, c): (A, B, C)) -> Self {
723        Value::Tuple(alloc::vec![a.into(), b.into(), c.into()])
724    }
725}
726
727impl<
728        A: TryFrom<Value, Error = ConversionError>,
729        B: TryFrom<Value, Error = ConversionError>,
730        C: TryFrom<Value, Error = ConversionError>,
731    > TryFrom<Value> for (A, B, C)
732{
733    type Error = ConversionError;
734    fn try_from(v: Value) -> Result<Self, Self::Error> {
735        match v {
736            Value::Tuple(mut items) if items.len() == 3 => {
737                let c = C::try_from(items.remove(2))
738                    .map_err(|e| ConversionError::IndexError(2, Box::new(e)))?;
739                let b = B::try_from(items.remove(1))
740                    .map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
741                let a = A::try_from(items.remove(0))
742                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
743                Ok((a, b, c))
744            }
745            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
746        }
747    }
748}
749
750// 4-tuple
751impl<A: Into<Value>, B: Into<Value>, C: Into<Value>, D: Into<Value>> From<(A, B, C, D)> for Value {
752    fn from((a, b, c, d): (A, B, C, D)) -> Self {
753        Value::Tuple(alloc::vec![a.into(), b.into(), c.into(), d.into()])
754    }
755}
756
757impl<
758        A: TryFrom<Value, Error = ConversionError>,
759        B: TryFrom<Value, Error = ConversionError>,
760        C: TryFrom<Value, Error = ConversionError>,
761        D: TryFrom<Value, Error = ConversionError>,
762    > TryFrom<Value> for (A, B, C, D)
763{
764    type Error = ConversionError;
765    fn try_from(v: Value) -> Result<Self, Self::Error> {
766        match v {
767            Value::Tuple(mut items) if items.len() == 4 => {
768                let d = D::try_from(items.remove(3))
769                    .map_err(|e| ConversionError::IndexError(3, Box::new(e)))?;
770                let c = C::try_from(items.remove(2))
771                    .map_err(|e| ConversionError::IndexError(2, Box::new(e)))?;
772                let b = B::try_from(items.remove(1))
773                    .map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
774                let a = A::try_from(items.remove(0))
775                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
776                Ok((a, b, c, d))
777            }
778            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
779        }
780    }
781}
782
783// ============================================================================
784// Result conversions (now using Value::Result directly)
785// ============================================================================
786
787impl<T: Into<Value>, E: Into<Value>> From<core::result::Result<T, E>> for Value {
788    fn from(r: core::result::Result<T, E>) -> Self {
789        match r {
790            Ok(v) => {
791                let val: Value = v.into();
792                let ok_type = val.infer_type();
793                Value::Result {
794                    ok_type,
795                    err_type: ValueType::String, // Default error type
796                    value: Ok(Box::new(val)),
797                }
798            }
799            Err(e) => {
800                let val: Value = e.into();
801                let err_type = val.infer_type();
802                Value::Result {
803                    ok_type: ValueType::S32, // Default ok type
804                    err_type,
805                    value: Err(Box::new(val)),
806                }
807            }
808        }
809    }
810}
811
812// Note: TryFrom<Value> for Result<T, E> is NOT implemented directly.
813// Use FromValue::from_value() instead, which supports nested Option types.
814// The FromValue impl for Result<T, E> is above with the other FromValue impls.
815
816use alloc::format;