Skip to main content

vtcode_commons/
serde_helpers.rs

1//! Serde helper utilities
2
3use serde::{Deserialize, Deserializer};
4use std::fmt::Display;
5use std::str::FromStr;
6
7/// Render a `serde_json::Value` as pretty-printed JSON, falling back to its
8/// `Display` impl when the value cannot be serialized.
9///
10/// This is the standard fallback used across the workspace for log lines and
11/// spooled output where we want a readable form but still want a non-empty
12/// string even for exotic value shapes.
13pub fn json_to_string_pretty(value: &serde_json::Value) -> String {
14    serde_json::to_string_pretty(value).unwrap_or_else(|_| value.to_string())
15}
16
17/// Deserializes a value that can be represented as either its native type or a quoted string.
18/// This is particularly useful for LLM tool calls which sometimes quote numeric arguments.
19pub fn deserialize_maybe_quoted<'de, T, D>(deserializer: D) -> Result<T, D::Error>
20where
21    T: FromStr + Deserialize<'de>,
22    T::Err: Display,
23    D: Deserializer<'de>,
24{
25    #[derive(Deserialize)]
26    #[serde(untagged)]
27    enum MaybeQuoted<T> {
28        Native(T),
29        Quoted(String),
30    }
31
32    match MaybeQuoted::<T>::deserialize(deserializer)? {
33        MaybeQuoted::Native(val) => Ok(val),
34        MaybeQuoted::Quoted(s) => T::from_str(&s).map_err(serde::de::Error::custom),
35    }
36}
37
38/// Deserializes an optional value that can be represented as either its native type or a quoted string.
39pub fn deserialize_opt_maybe_quoted<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
40where
41    T: FromStr + Deserialize<'de>,
42    T::Err: Display,
43    D: Deserializer<'de>,
44{
45    #[derive(Deserialize)]
46    #[serde(untagged)]
47    enum MaybeQuoted<T> {
48        Native(T),
49        Quoted(String),
50        Null,
51    }
52
53    match MaybeQuoted::<T>::deserialize(deserializer)? {
54        MaybeQuoted::Native(val) => Ok(Some(val)),
55        MaybeQuoted::Quoted(s) => T::from_str(&s).map(Some).map_err(serde::de::Error::custom),
56        MaybeQuoted::Null => Ok(None),
57    }
58}