Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T03:38:40.695Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

fallible_options.rs

113 lines · 2.9 KB · rust
1use std::cell::RefCell;
2
3use serde::Deserialize;
4
5use crate::ParseStatus;
6
7thread_local! {
8    static ERRORS: RefCell<Option<Vec<anyhow::Error>>> = const { RefCell::new(None) };
9}
10
11pub fn parse_json<'de, T>(json: &'de str) -> (Option<T>, ParseStatus)
12where
13    T: Deserialize<'de>,
14{
15    ERRORS.with_borrow_mut(|errors| {
16        errors.replace(Vec::default());
17    });
18
19    let mut deserializer = serde_json_lenient::Deserializer::from_str(json);
20    let value = T::deserialize(&mut deserializer);
21    let value = match value {
22        Ok(value) => value,
23        Err(error) => {
24            return (
25                None,
26                ParseStatus::Failed {
27                    error: error.to_string(),
28                },
29            );
30        }
31    };
32
33    if let Some(errors) = ERRORS.with_borrow_mut(|errors| errors.take().filter(|e| !e.is_empty())) {
34        let error = errors
35            .into_iter()
36            .map(|e| e.to_string())
37            .flat_map(|e| ["\n".to_owned(), e])
38            .skip(1)
39            .collect::<String>();
40        return (Some(value), ParseStatus::Failed { error });
41    }
42
43    (Some(value), ParseStatus::Success)
44}
45
46pub(crate) fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
47where
48    D: serde::Deserializer<'de>,
49    T: serde::Deserialize<'de> + FallibleOption,
50{
51    match T::deserialize(deserializer) {
52        Ok(value) => Ok(value),
53        Err(e) => ERRORS.with_borrow_mut(|errors| {
54            if let Some(errors) = errors {
55                errors.push(anyhow::anyhow!("{}", e));
56                Ok(Default::default())
57            } else {
58                Err(e)
59            }
60        }),
61    }
62}
63
64pub trait FallibleOption: Default {}
65impl<T> FallibleOption for Option<T> {}
66
67#[cfg(test)]
68mod tests {
69    use serde::Deserialize;
70    use settings_macros::with_fallible_options;
71
72    use crate::ParseStatus;
73
74    #[with_fallible_options]
75    #[derive(Deserialize, Debug, PartialEq)]
76    struct Foo {
77        foo: Option<String>,
78        bar: Option<usize>,
79        baz: Option<bool>,
80    }
81
82    #[test]
83    fn test_fallible() {
84        let input = r#"
85            {"foo": "bar",
86            "bar": "foo",
87            "baz": 3,
88            }
89        "#;
90
91        let (settings, result) = crate::fallible_options::parse_json::<Foo>(&input);
92        assert_eq!(
93            settings.unwrap(),
94            Foo {
95                foo: Some("bar".into()),
96                bar: None,
97                baz: None,
98            }
99        );
100
101        assert!(settings_json::parse_json_with_comments::<Foo>(&input).is_err());
102
103        let ParseStatus::Failed { error } = result else {
104            panic!("Expected parse to fail")
105        };
106
107        assert_eq!(
108            error,
109            "invalid type: string \"foo\", expected usize at line 3 column 24\ninvalid type: integer `3`, expected a boolean at line 4 column 20".to_string()
110        )
111    }
112}
113
Served at tenant.openagents/omega Member data and write actions are omitted.