Skip to main content

typesafe_rs/types/
entry.rs

1use std::borrow::Cow;
2
3use serde::{Deserialize, Serialize};
4
5/// Text, structured JSON, or `null` for state, instructions, and criteria.
6///
7/// Matches TypeSafe's `string | object | array | null` entry type.
8#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
9#[serde(untagged)]
10pub enum Entry {
11    /// A text instruction or description.
12    Text(Cow<'static, str>),
13    /// JSON `null`.
14    #[default]
15    Null,
16    /// A JSON object, array, number, or boolean.
17    Json(serde_json::Value),
18}
19
20impl From<&'static str> for Entry {
21    fn from(value: &'static str) -> Self {
22        Self::Text(Cow::Borrowed(value))
23    }
24}
25
26impl From<String> for Entry {
27    fn from(value: String) -> Self {
28        Self::Text(Cow::Owned(value))
29    }
30}
31
32impl From<&String> for Entry {
33    fn from(value: &String) -> Self {
34        Self::Text(Cow::Owned(value.clone()))
35    }
36}
37
38impl From<serde_json::Value> for Entry {
39    fn from(value: serde_json::Value) -> Self {
40        match value {
41            serde_json::Value::Null => Self::Null,
42            serde_json::Value::String(s) => Self::Text(Cow::Owned(s)),
43            other => Self::Json(other),
44        }
45    }
46}
47
48impl From<Option<String>> for Entry {
49    fn from(value: Option<String>) -> Self {
50        match value {
51            Some(s) => Self::from(s),
52            None => Self::Null,
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use serde_json::json;
61
62    #[test]
63    fn text_roundtrip() {
64        let entry = Entry::from("hello");
65        let value = serde_json::to_value(&entry).unwrap();
66        assert_eq!(value, json!("hello"));
67        let back: Entry = serde_json::from_value(value).unwrap();
68        assert_eq!(back, Entry::from("hello"));
69    }
70
71    #[test]
72    fn null_roundtrip() {
73        let value = serde_json::to_value(Entry::Null).unwrap();
74        assert_eq!(value, json!(null));
75        let back: Entry = serde_json::from_value(json!(null)).unwrap();
76        assert_eq!(back, Entry::Null);
77    }
78
79    #[test]
80    fn object_roundtrip() {
81        let entry = Entry::from(json!({"question": "urgent?"}));
82        let value = serde_json::to_value(&entry).unwrap();
83        assert_eq!(value, json!({"question": "urgent?"}));
84    }
85
86    #[test]
87    fn array_roundtrip() {
88        let entry = Entry::from(json!(["a", "b"]));
89        let value = serde_json::to_value(&entry).unwrap();
90        assert_eq!(value, json!(["a", "b"]));
91    }
92
93    #[test]
94    fn from_value_null_is_null_variant() {
95        assert_eq!(Entry::from(serde_json::Value::Null), Entry::Null);
96    }
97}