1use serde::de::DeserializeOwned;
4use serde::Serialize;
5use serde_json::Value;
6
7use crate::error::FMError;
8
9pub trait FromGeneratedContent: Sized {
11 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError>;
13}
14
15pub trait ToGeneratedContent {
17 fn to_generated_content(&self) -> Result<GeneratedContent, FMError>;
19}
20
21#[derive(Debug, Clone, PartialEq)]
26pub struct GeneratedContent {
27 value: Value,
28 generation_id: Option<String>,
29 is_complete: bool,
30}
31
32impl GeneratedContent {
33 pub fn from_json_str(json: &str) -> Result<Self, FMError> {
39 let value = serde_json::from_str(json).map_err(|error| {
40 FMError::InvalidArgument(format!("generated content JSON is invalid: {error}"))
41 })?;
42 Ok(Self {
43 value,
44 generation_id: None,
45 is_complete: true,
46 })
47 }
48
49 pub fn from_value<T>(value: T) -> Result<Self, FMError>
55 where
56 T: Serialize,
57 {
58 let value = serde_json::to_value(value).map_err(|error| {
59 FMError::InvalidArgument(format!(
60 "generated content value is not JSON-serializable: {error}"
61 ))
62 })?;
63 Ok(Self {
64 value,
65 generation_id: None,
66 is_complete: true,
67 })
68 }
69
70 pub(crate) fn from_bridge_json(
72 json: &str,
73 is_complete: bool,
74 generation_id: Option<String>,
75 ) -> Result<Self, FMError> {
76 let mut content = Self::from_json_str(json)?;
77 content.is_complete = is_complete;
78 content.generation_id = generation_id;
79 Ok(content)
80 }
81
82 #[must_use]
84 pub const fn raw_value(&self) -> &Value {
85 &self.value
86 }
87
88 #[must_use]
90 pub fn into_raw_value(self) -> Value {
91 self.value
92 }
93
94 pub fn json_string(&self) -> Result<String, FMError> {
100 serde_json::to_string(&self.value).map_err(|error| FMError::Unknown {
101 code: crate::ffi::status::UNKNOWN,
102 message: format!("failed to serialize generated content: {error}"),
103 })
104 }
105
106 pub fn json_string_pretty(&self) -> Result<String, FMError> {
112 serde_json::to_string_pretty(&self.value).map_err(|error| FMError::Unknown {
113 code: crate::ffi::status::UNKNOWN,
114 message: format!("failed to serialize generated content: {error}"),
115 })
116 }
117
118 pub fn value<T>(&self) -> Result<T, FMError>
124 where
125 T: DeserializeOwned,
126 {
127 serde_json::from_value(self.value.clone())
128 .map_err(|error| FMError::DecodingFailure(error.to_string()))
129 }
130
131 pub fn value_for_property<T>(&self, property: &str) -> Result<T, FMError>
138 where
139 T: DeserializeOwned,
140 {
141 let Value::Object(map) = &self.value else {
142 return Err(FMError::DecodingFailure(
143 "generated content is not an object".into(),
144 ));
145 };
146 let value = map.get(property).cloned().ok_or_else(|| {
147 FMError::DecodingFailure(format!(
148 "generated content is missing property `{property}`"
149 ))
150 })?;
151 serde_json::from_value(value).map_err(|error| FMError::DecodingFailure(error.to_string()))
152 }
153
154 #[must_use]
156 pub const fn is_complete(&self) -> bool {
157 self.is_complete
158 }
159
160 #[must_use]
162 pub fn generation_id(&self) -> Option<&str> {
163 self.generation_id.as_deref()
164 }
165}
166
167impl TryFrom<Value> for GeneratedContent {
168 type Error = FMError;
169
170 fn try_from(value: Value) -> Result<Self, Self::Error> {
171 Ok(Self {
172 value,
173 generation_id: None,
174 is_complete: true,
175 })
176 }
177}
178
179impl From<GeneratedContent> for Value {
180 fn from(value: GeneratedContent) -> Self {
181 value.value
182 }
183}
184
185macro_rules! impl_scalar_content {
186 ($($ty:ty),+ $(,)?) => {
187 $(
188 impl From<$ty> for GeneratedContent {
189 fn from(value: $ty) -> Self {
190 Self {
191 value: serde_json::to_value(value)
192 .expect("scalar values must always be JSON-serializable"),
193 generation_id: None,
194 is_complete: true,
195 }
196 }
197 }
198 )+
199 };
200}
201
202impl_scalar_content!(bool, f32, f64, i8, i16, i32, i64, u8, u16, u32, u64);
203
204impl From<String> for GeneratedContent {
205 fn from(value: String) -> Self {
206 Self {
207 value: Value::String(value),
208 generation_id: None,
209 is_complete: true,
210 }
211 }
212}
213
214impl From<&str> for GeneratedContent {
215 fn from(value: &str) -> Self {
216 Self::from(value.to_owned())
217 }
218}
219
220impl<T> From<Vec<T>> for GeneratedContent
221where
222 T: Into<GeneratedContent>,
223{
224 fn from(values: Vec<T>) -> Self {
225 Self {
226 value: Value::Array(values.into_iter().map(|value| value.into().value).collect()),
227 generation_id: None,
228 is_complete: true,
229 }
230 }
231}
232
233impl FromGeneratedContent for GeneratedContent {
234 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError> {
235 Ok(content.clone())
236 }
237}
238
239impl ToGeneratedContent for GeneratedContent {
240 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
241 Ok(self.clone())
242 }
243}
244
245impl FromGeneratedContent for Value {
246 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError> {
247 Ok(content.raw_value().clone())
248 }
249}
250
251impl ToGeneratedContent for Value {
252 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
253 GeneratedContent::from_value(self)
254 }
255}
256
257impl FromGeneratedContent for String {
258 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError> {
259 content.value()
260 }
261}
262
263impl ToGeneratedContent for String {
264 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
265 Ok(GeneratedContent::from(self.clone()))
266 }
267}
268
269impl ToGeneratedContent for str {
270 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
271 Ok(GeneratedContent::from(self))
272 }
273}
274
275impl FromGeneratedContent for bool {
276 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError> {
277 content.value()
278 }
279}
280
281impl ToGeneratedContent for bool {
282 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
283 Ok(GeneratedContent::from(*self))
284 }
285}
286
287macro_rules! impl_numeric_conversion {
288 ($($ty:ty),+ $(,)?) => {
289 $(
290 impl FromGeneratedContent for $ty {
291 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError> {
292 content.value()
293 }
294 }
295
296 impl ToGeneratedContent for $ty {
297 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
298 Ok(GeneratedContent::from(*self))
299 }
300 }
301 )+
302 };
303}
304
305impl_numeric_conversion!(f32, f64, i8, i16, i32, i64, u8, u16, u32, u64);
306
307impl<T> FromGeneratedContent for Vec<T>
308where
309 T: FromGeneratedContent,
310{
311 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError> {
312 let values: Vec<Value> = content.value()?;
313 values
314 .iter()
315 .map(|value| {
316 let nested = GeneratedContent::try_from(value.clone())?;
317 T::from_generated_content(&nested)
318 })
319 .collect()
320 }
321}
322
323impl<T> ToGeneratedContent for Vec<T>
324where
325 T: ToGeneratedContent,
326{
327 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
328 let values = self
329 .iter()
330 .map(ToGeneratedContent::to_generated_content)
331 .collect::<Result<Vec<_>, _>>()?;
332 Ok(GeneratedContent {
333 value: Value::Array(
334 values
335 .into_iter()
336 .map(GeneratedContent::into_raw_value)
337 .collect(),
338 ),
339 generation_id: None,
340 is_complete: true,
341 })
342 }
343}
344
345impl<T> FromGeneratedContent for Option<T>
346where
347 T: FromGeneratedContent,
348{
349 fn from_generated_content(content: &GeneratedContent) -> Result<Self, FMError> {
350 if content.raw_value().is_null() {
351 return Ok(None);
352 }
353 T::from_generated_content(content).map(Some)
354 }
355}
356
357impl<T> ToGeneratedContent for Option<T>
358where
359 T: ToGeneratedContent,
360{
361 fn to_generated_content(&self) -> Result<GeneratedContent, FMError> {
362 match self {
363 Some(value) => value.to_generated_content(),
364 None => GeneratedContent::from_value(Option::<Value>::None),
365 }
366 }
367}