1use core::fmt;
2use indexmap::{Equivalent, IndexMap};
3use linked_data::{LinkedData, LinkedDataGraph};
4use rdf_types::{Interpretation, Vocabulary};
5use serde::{Deserialize, Serialize};
6use std::hash::Hash;
7
8use crate::StructName;
9
10mod deserialize;
11mod serialize;
12
13pub use serialize::{to_struct, to_value, InvalidValue};
14
15#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
17#[serde(transparent)]
18pub struct Struct(IndexMap<String, Value>);
19
20impl Struct {
21 pub fn new() -> Self {
22 Self::default()
23 }
24
25 pub fn with_capacity(cap: usize) -> Self {
26 Self(IndexMap::with_capacity(cap))
27 }
28
29 pub fn is_empty(&self) -> bool {
30 self.0.is_empty()
31 }
32
33 pub fn len(&self) -> usize {
34 self.0.len()
35 }
36
37 pub fn get(&self, key: &(impl ?Sized + Hash + Equivalent<String>)) -> Option<&Value> {
38 self.0.get(key)
39 }
40
41 pub fn get_mut(
42 &mut self,
43 key: &(impl ?Sized + Hash + Equivalent<String>),
44 ) -> Option<&mut Value> {
45 self.0.get_mut(key)
46 }
47
48 pub fn iter(&self) -> indexmap::map::Iter<String, Value> {
49 self.0.iter()
50 }
51
52 pub fn keys(&self) -> indexmap::map::Keys<String, Value> {
53 self.0.keys()
54 }
55
56 pub fn insert(&mut self, name: String, value: Value) -> Option<Value> {
57 self.0.insert(name, value)
58 }
59}
60
61impl IntoIterator for Struct {
62 type IntoIter = indexmap::map::IntoIter<String, Value>;
63 type Item = (String, Value);
64
65 fn into_iter(self) -> Self::IntoIter {
66 self.0.into_iter()
67 }
68}
69
70impl<'a> IntoIterator for &'a Struct {
71 type IntoIter = indexmap::map::Iter<'a, String, Value>;
72 type Item = (&'a String, &'a Value);
73
74 fn into_iter(self) -> Self::IntoIter {
75 self.0.iter()
76 }
77}
78
79impl FromIterator<(StructName, Value)> for Struct {
80 fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
81 Self(IndexMap::from_iter(iter))
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
86pub enum ValueKind {
87 String,
88 Bytes,
89 Array,
90 Struct,
91 Bool,
92 Integer,
93}
94
95impl ValueKind {
96 pub fn as_str(&self) -> &'static str {
97 match self {
98 Self::String => "string",
99 Self::Bytes => "bytes",
100 Self::Array => "array",
101 Self::Struct => "struct",
102 Self::Bool => "bool",
103 Self::Integer => "integer",
104 }
105 }
106
107 pub fn into_str(self) -> &'static str {
108 self.as_str()
109 }
110}
111
112impl fmt::Display for ValueKind {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 self.as_str().fmt(f)
115 }
116}
117
118#[derive(Debug, Clone, PartialEq, Eq)]
120pub enum Value {
121 String(String),
122 Bytes(Vec<u8>),
123 Array(Vec<Value>),
124 Struct(Struct),
125 Bool(bool),
126 Integer(i64),
127}
128
129impl Value {
130 pub fn kind(&self) -> ValueKind {
131 match self {
132 Self::String(_) => ValueKind::String,
133 Self::Bytes(_) => ValueKind::Bytes,
134 Self::Array(_) => ValueKind::Array,
135 Self::Struct(_) => ValueKind::Struct,
136 Self::Bool(_) => ValueKind::Bool,
137 Self::Integer(_) => ValueKind::Integer,
138 }
139 }
140
141 pub fn as_bool(&self) -> Option<bool> {
142 match self {
143 Value::Bool(b) => Some(*b),
144 Value::String(string) => {
145 match &string[..] {
149 "" => Some(false),
150 "true" => Some(true),
151 "1" => Some(true),
152 _ => None,
153 }
154 }
155 Value::Integer(int) => match int {
156 0 => Some(false),
157 1 => Some(true),
158 _ => None,
159 },
160 _ => None,
161 }
162 }
163
164 pub fn as_struct(&self) -> Option<&Struct> {
165 match self {
166 Value::Struct(map) => Some(map),
167 _ => None,
168 }
169 }
170
171 pub fn as_struct_mut(&mut self) -> Option<&mut Struct> {
172 match self {
173 Value::Struct(map) => Some(map),
174 _ => None,
175 }
176 }
177}
178
179impl From<Value> for serde_json::Value {
180 fn from(value: Value) -> serde_json::Value {
181 match value {
182 Value::Bool(true) => serde_json::Value::Bool(true),
183 Value::Bool(false) => serde_json::Value::Bool(false),
184 Value::Integer(int) => serde_json::Value::Number(serde_json::Number::from(int)),
185 Value::Bytes(bytes) => {
186 serde_json::Value::String("0x".to_string() + &hex::encode(bytes))
187 }
188 Value::String(string) => serde_json::Value::String(string),
189 Value::Array(array) => {
190 serde_json::Value::Array(array.into_iter().map(serde_json::Value::from).collect())
191 }
192 Value::Struct(hash_map) => serde_json::Value::Object(
193 hash_map
194 .into_iter()
195 .map(|(name, value)| (name, serde_json::Value::from(value)))
196 .collect(),
197 ),
198 }
199 }
200}
201
202linked_data::json_literal!(Value);
203
204impl<V: Vocabulary, I: Interpretation> LinkedDataGraph<I, V> for Value {
205 fn visit_graph<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
206 where
207 S: linked_data::GraphVisitor<I, V>,
208 {
209 visitor.subject(self)?;
210 visitor.end()
211 }
212}
213
214impl<V: Vocabulary, I: Interpretation> LinkedData<I, V> for Value {
215 fn visit<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
216 where
217 S: linked_data::Visitor<I, V>,
218 {
219 visitor.default_graph(self)?;
220 visitor.end()
221 }
222}
223
224#[derive(Debug, thiserror::Error)]
225pub enum FromJsonError {
226 #[error("Unexpected null value")]
227 UnexpectedNull,
228 #[error("Unexpected number: {0:?}")]
229 Number(serde_json::Number),
230}
231
232impl TryFrom<serde_json::Value> for Value {
233 type Error = FromJsonError;
234
235 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
236 let eip712_value = match value {
237 serde_json::Value::Null => return Err(Self::Error::UnexpectedNull),
238 serde_json::Value::Bool(true) => Value::Bool(true),
239 serde_json::Value::Bool(false) => Value::Bool(false),
240 serde_json::Value::String(string) => Value::String(string),
241 serde_json::Value::Number(number) => {
242 if let Some(int) = number.as_i64() {
243 Value::Integer(int)
244 } else {
245 return Err(Self::Error::Number(number));
246 }
247 }
248 serde_json::Value::Array(array) => Value::Array(
249 array
250 .into_iter()
251 .map(Value::try_from)
252 .collect::<Result<Vec<Self>, Self::Error>>()?,
253 ),
254 serde_json::Value::Object(object) => Value::Struct(
255 object
256 .into_iter()
257 .map(|(name, value)| Value::try_from(value).map(|v| (name, v)))
258 .collect::<Result<Struct, Self::Error>>()?,
259 ),
260 };
261
262 Ok(eip712_value)
263 }
264}