1#![deny(
20 missing_copy_implementations,
21 trivial_casts,
22 trivial_numeric_casts,
23 unsafe_code,
24 unused_import_braces,
25 unused_qualifications
26)]
27use serde::{Deserialize, Serialize};
30pub use url::Url;
31
32use std::collections::HashMap;
33pub use std::convert::TryFrom;
34
35pub mod error;
36pub mod id;
37pub mod property;
38mod validation;
39
40use crate::error::Result;
41use crate::id::*;
42use crate::property::*;
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
47pub struct Schema(SchemaInner);
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
52#[serde(untagged)]
53enum SchemaInner {
54 Schema(SchemaDefinition),
56 Boolean(bool),
58}
59
60impl Schema {
61 pub fn draft_version(&self) -> Option<&str> {
62 match &self.0 {
63 SchemaInner::Schema(SchemaDefinition {
64 schema: Some(schema),
65 ..
66 }) => schema
67 .path_segments()
68 .and_then(|mut segments| segments.next()),
69 _ => None,
70 }
71 }
72
73 fn as_definition(&self) -> Option<&SchemaDefinition> {
74 match &self.0 {
75 SchemaInner::Schema(definition @ SchemaDefinition { .. }) => Some(definition),
76 _ => None,
77 }
78 }
79
80 pub fn id(&self) -> Option<&SchemaId> {
81 self.as_definition().and_then(|d| d.id.as_ref())
82 }
83
84 pub fn schema(&self) -> Option<&Url> {
85 self.as_definition().and_then(|d| d.schema.as_ref())
86 }
87
88 pub fn description(&self) -> Option<&str> {
89 self.as_definition().and_then(|d| d.description.as_deref())
90 }
91
92 pub fn specification(&self) -> Option<&PropertyInstance> {
93 match &self.0 {
94 SchemaInner::Schema(SchemaDefinition {
95 specification:
96 Some(Property::Value(specification @ PropertyInstance::Object { .. })),
97 ..
98 }) => Some(specification),
99 SchemaInner::Schema(SchemaDefinition {
100 specification: Some(Property::Value(specification @ PropertyInstance::Array { .. })),
101 ..
102 }) => Some(specification),
103 _ => None,
104 }
105 }
106
107 pub fn properties(&self) -> Option<&HashMap<String, Property>> {
108 match self.specification() {
109 Some(PropertyInstance::Object { properties, .. }) => Some(properties),
110 _ => None,
111 }
112 }
113
114 pub fn required_properties(&self) -> Option<&Vec<String>> {
115 match self.specification() {
116 Some(PropertyInstance::Object { required, .. }) => required.as_ref(),
117 _ => None,
118 }
119 }
120
121 pub fn as_null(&self) -> Option<&PropertyInstance> {
122 match self.specification() {
123 Some(null @ PropertyInstance::Null) => Some(null),
124 _ => None,
125 }
126 }
127
128 pub fn as_boolean(&self) -> Option<&PropertyInstance> {
129 match self.specification() {
130 Some(boolean @ PropertyInstance::Boolean) => Some(boolean),
131 _ => None,
132 }
133 }
134
135 pub fn as_integer(&self) -> Option<&PropertyInstance> {
136 match self.specification() {
137 Some(integer @ PropertyInstance::Integer { .. }) => Some(integer),
138 _ => None,
139 }
140 }
141
142 pub fn as_object(&self) -> Option<&PropertyInstance> {
143 match self.specification() {
144 Some(object @ PropertyInstance::Object { .. }) => Some(object),
145 _ => None,
146 }
147 }
148
149 pub fn as_array(&self) -> Option<&PropertyInstance> {
150 match self.specification() {
151 Some(array @ PropertyInstance::Array { .. }) => Some(array),
152 _ => None,
153 }
154 }
155
156 pub fn as_number(&self) -> Option<&PropertyInstance> {
157 match self.specification() {
158 Some(number @ PropertyInstance::Number { .. }) => Some(number),
159 _ => None,
160 }
161 }
162
163 pub fn validate(&self, json: &serde_json::Value) -> std::result::Result<(), Vec<String>> {
164 match self.0 {
165 SchemaInner::Schema(SchemaDefinition {
166 specification: Some(Property::Value(ref prop)),
167 ..
168 }) => prop.validate(json),
169 SchemaInner::Schema(SchemaDefinition {
170 specification: Some(Property::Ref(_)),
171 ..
172 }) => unimplemented!(),
173 SchemaInner::Boolean(true) => {
174 eprintln!(r#"your schema is just "true", everything goes"#);
175 Ok(())
176 }
177 SchemaInner::Boolean(false) => Err(vec![String::from(
178 r#""the scheme "false" will never validate"#,
179 )]),
180 _ => Ok(()),
181 }
182 }
183}
184
185impl TryFrom<serde_json::Value> for Schema {
186 type Error = crate::error::Error;
187 fn try_from(v: serde_json::Value) -> Result<Schema> {
188 Ok(serde_json::from_value(v)?)
189 }
190}
191
192impl TryFrom<&str> for Schema {
193 type Error = crate::error::Error;
194 fn try_from(s: &str) -> Result<Schema> {
195 Ok(serde_json::from_str(s)?)
196 }
197}
198
199impl TryFrom<String> for Schema {
200 type Error = crate::error::Error;
201 fn try_from(s: String) -> Result<Schema> {
202 Ok(serde_json::from_str(&s)?)
203 }
204}
205
206impl TryFrom<&str> for SchemaDefinition {
207 type Error = crate::error::Error;
208 fn try_from(s: &str) -> Result<SchemaDefinition> {
209 Ok(serde_json::from_str(s)?)
210 }
211}
212
213impl TryFrom<String> for SchemaDefinition {
214 type Error = crate::error::Error;
215 fn try_from(s: String) -> Result<SchemaDefinition> {
216 Ok(serde_json::from_str(&s)?)
217 }
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
222pub(crate) struct SchemaDefinition {
223 #[serde(rename = "$id")]
224 pub id: Option<SchemaId>,
225
226 #[serde(rename = "$schema")]
227 pub schema: Option<Url>,
228 pub description: Option<String>,
229 pub dependencies: Option<HashMap<String, Vec<String>>>,
231
232 #[serde(flatten)]
233 pub specification: Option<Property>,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub definitions: Option<HashMap<String, SchemaDefinition>>,
237}