baml/codec/
from_baml_value.rs

1//! Trait for extracting concrete types from `BamlValue` (owned).
2
3use super::{baml_value::BamlValue, known_types::KnownTypes};
4use crate::error::BamlError;
5
6/// Trait for extracting concrete types from `BamlValue`.
7///
8/// Primitives are implemented in the baml crate.
9/// Known types are implemented by generated code.
10pub trait FromBamlValue<T: KnownTypes, S: KnownTypes>: Sized {
11    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError>;
12}
13
14// =============================================================================
15// Primitive FromBamlValue implementations
16// =============================================================================
17
18impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for String {
19    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
20        match value {
21            BamlValue::String(s) => Ok(s),
22            other => Err(BamlError::type_check::<Self>(&other)),
23        }
24    }
25}
26
27impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for i64 {
28    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
29        match value {
30            BamlValue::Int(i) => Ok(i),
31            other => Err(BamlError::type_check::<Self>(&other)),
32        }
33    }
34}
35
36impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for f64 {
37    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
38        match value {
39            BamlValue::Float(f) => Ok(f),
40            other => Err(BamlError::type_check::<Self>(&other)),
41        }
42    }
43}
44
45impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for bool {
46    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
47        match value {
48            BamlValue::Bool(b) => Ok(b),
49            other => Err(BamlError::type_check::<Self>(&other)),
50        }
51    }
52}
53
54impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for () {
55    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
56        match value {
57            BamlValue::Null => Ok(()),
58            other => Err(BamlError::type_check::<Self>(&other)),
59        }
60    }
61}
62
63// =============================================================================
64// Identity and Dynamic Type FromBamlValue implementations
65// =============================================================================
66
67use super::dynamic_types::{DynamicClass, DynamicEnum, DynamicUnion};
68
69/// Identity impl - extract `BamlValue` from `BamlValue`
70impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for BamlValue<T, S> {
71    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
72        Ok(value)
73    }
74}
75
76/// `DynamicClass` extraction
77impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for DynamicClass<T, S> {
78    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
79        match value {
80            BamlValue::DynamicClass(dc) => Ok(dc),
81            other => Err(BamlError::type_check::<Self>(&other)),
82        }
83    }
84}
85
86/// `DynamicEnum` extraction
87impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for DynamicEnum {
88    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
89        match value {
90            BamlValue::DynamicEnum(de) => Ok(de),
91            other => Err(BamlError::type_check::<Self>(&other)),
92        }
93    }
94}
95
96/// `DynamicUnion` extraction
97impl<T: KnownTypes, S: KnownTypes> FromBamlValue<T, S> for DynamicUnion<T, S> {
98    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
99        match value {
100            BamlValue::DynamicUnion(du) => Ok(du),
101            other => Err(BamlError::type_check::<Self>(&other)),
102        }
103    }
104}
105
106// =============================================================================
107// Container FromBamlValue blanket implementations
108// =============================================================================
109
110use std::collections::HashMap;
111
112use crate::error::BamlTypeName;
113
114/// Option<V> - handles nullable fields (string?, int?, etc.)
115/// Note: `BamlTypeName` bound is for consistency with Vec/HashMap, even though
116/// Option never produces type errors itself (it delegates to V or returns None
117/// for Null).
118impl<T: KnownTypes, S: KnownTypes, V: FromBamlValue<T, S> + BamlTypeName> FromBamlValue<T, S>
119    for Option<V>
120{
121    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
122        match value {
123            BamlValue::Null => Ok(None),
124            other => Ok(Some(V::from_baml_value(other)?)),
125        }
126    }
127}
128
129/// Vec<V> - handles list types (string[], Person[], etc.)
130impl<T: KnownTypes, S: KnownTypes, V: FromBamlValue<T, S> + BamlTypeName> FromBamlValue<T, S>
131    for Vec<V>
132{
133    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
134        match value {
135            BamlValue::List(list) => list.into_iter().map(V::from_baml_value).collect(),
136            other => Err(BamlError::type_check::<Self>(&other)),
137        }
138    }
139}
140
141/// `HashMap`<String, V> - handles map types (map<string, int>, etc.)
142impl<T: KnownTypes, S: KnownTypes, V: FromBamlValue<T, S> + BamlTypeName> FromBamlValue<T, S>
143    for HashMap<String, V>
144{
145    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
146        match value {
147            BamlValue::Map(map) => map
148                .into_iter()
149                .map(|(k, v)| Ok((k, V::from_baml_value(v)?)))
150                .collect(),
151            other => Err(BamlError::type_check::<Self>(&other)),
152        }
153    }
154}
155
156// =============================================================================
157// Wrapper type blanket implementations
158// =============================================================================
159
160use crate::types::{Checked, StreamState, StreamingState};
161
162/// Checked<V> blanket impl - works for any V: `FromBamlValue`
163impl<T: KnownTypes, S: KnownTypes, V: FromBamlValue<T, S>> FromBamlValue<T, S> for Checked<V> {
164    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
165        match value {
166            BamlValue::Checked(checked) => {
167                // Extract inner BamlValue, convert to V
168                let inner = V::from_baml_value(*checked.value)?;
169                Ok(Checked {
170                    value: inner,
171                    checks: checked.checks,
172                })
173            }
174            // Allow unwrapped value (no checks = empty checks)
175            other => {
176                let inner = V::from_baml_value(other)?;
177                Ok(Checked {
178                    value: inner,
179                    checks: HashMap::new(),
180                })
181            }
182        }
183    }
184}
185
186/// `StreamState`<V> blanket impl - works for any V: `FromBamlValue`
187impl<T: KnownTypes, S: KnownTypes, V: FromBamlValue<T, S>> FromBamlValue<T, S> for StreamState<V> {
188    fn from_baml_value(value: BamlValue<T, S>) -> Result<Self, BamlError> {
189        match value {
190            BamlValue::StreamState(ss) => Ok(StreamState {
191                value: V::from_baml_value(*ss.value)?,
192                state: ss.state,
193            }),
194            // Treat unwrapped as Done
195            other => Ok(StreamState {
196                value: V::from_baml_value(other)?,
197                state: StreamingState::Done,
198            }),
199        }
200    }
201}