vld/primitives/
literal.rs1use serde_json::Value;
2
3use crate::error::{IssueCode, VldError};
4use crate::schema::VldSchema;
5
6pub trait IntoLiteral: Clone + 'static {
8 type Output: Clone + PartialEq + std::fmt::Debug;
9 fn to_json_value(&self) -> Value;
10 fn extract(value: &Value) -> Option<Self::Output>;
11 fn display(&self) -> String;
12}
13
14impl IntoLiteral for &'static str {
15 type Output = String;
16 fn to_json_value(&self) -> Value {
17 Value::String(self.to_string())
18 }
19 fn extract(value: &Value) -> Option<String> {
20 value.as_str().map(|s| s.to_string())
21 }
22 fn display(&self) -> String {
23 format!("\"{}\"", self)
24 }
25}
26
27impl IntoLiteral for String {
28 type Output = String;
29 fn to_json_value(&self) -> Value {
30 Value::String(self.clone())
31 }
32 fn extract(value: &Value) -> Option<String> {
33 value.as_str().map(|s| s.to_string())
34 }
35 fn display(&self) -> String {
36 format!("\"{}\"", self)
37 }
38}
39
40impl IntoLiteral for i64 {
41 type Output = i64;
42 fn to_json_value(&self) -> Value {
43 Value::Number((*self).into())
44 }
45 fn extract(value: &Value) -> Option<i64> {
46 value.as_i64()
47 }
48 fn display(&self) -> String {
49 self.to_string()
50 }
51}
52
53impl IntoLiteral for f64 {
54 type Output = f64;
55 fn to_json_value(&self) -> Value {
56 serde_json::Number::from_f64(*self)
57 .map(Value::Number)
58 .unwrap_or(Value::Null)
59 }
60 fn extract(value: &Value) -> Option<f64> {
61 value.as_f64()
62 }
63 fn display(&self) -> String {
64 self.to_string()
65 }
66}
67
68impl IntoLiteral for bool {
69 type Output = bool;
70 fn to_json_value(&self) -> Value {
71 Value::Bool(*self)
72 }
73 fn extract(value: &Value) -> Option<bool> {
74 value.as_bool()
75 }
76 fn display(&self) -> String {
77 self.to_string()
78 }
79}
80
81pub struct ZLiteral<T: IntoLiteral> {
83 expected_value: Value,
84 display: String,
85 _phantom: std::marker::PhantomData<T>,
86}
87
88impl<T: IntoLiteral> ZLiteral<T> {
89 pub fn new(expected: T) -> Self {
90 let expected_value = expected.to_json_value();
91 let display = expected.display();
92 Self {
93 expected_value,
94 display,
95 _phantom: std::marker::PhantomData,
96 }
97 }
98}
99
100impl<T: IntoLiteral> VldSchema for ZLiteral<T> {
101 type Output = T::Output;
102
103 fn parse_value(&self, value: &Value) -> Result<T::Output, VldError> {
104 if *value == self.expected_value {
105 T::extract(value).ok_or_else(|| {
106 VldError::single(
107 IssueCode::Custom {
108 code: "invalid_literal".to_string(),
109 },
110 format!("Expected literal {}", self.display),
111 )
112 })
113 } else {
114 Err(VldError::single_with_value(
115 IssueCode::Custom {
116 code: "invalid_literal".to_string(),
117 },
118 format!("Expected literal {}, received {:?}", self.display, value),
119 value,
120 ))
121 }
122 }
123}