serde_json_schema/
id.rs

1//! Everything related to parsing schemaId
2
3use json_pointer::JsonPointer;
4use serde::de::{self, Deserialize, Deserializer, Visitor};
5use serde::ser::{Serialize, Serializer};
6use url::Url;
7
8use std::fmt;
9use std::str::FromStr;
10
11use crate::error::{InvalidFragment, InvalidPath};
12
13/// Either a `Url` or a `JsonPointer`
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum SchemaId {
16    Url(Url),
17    Pointer(JsonPointer<String, Vec<String>>),
18    Fragment(Fragment),
19    Path(Path),
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct Fragment(String);
24
25impl FromStr for Fragment {
26    type Err = InvalidFragment;
27
28    fn from_str(s: &str) -> Result<Self, Self::Err> {
29        match s.chars().nth(0) {
30            Some('#') => Ok(Fragment(s[1..].to_owned())),
31            _ => Err(InvalidFragment),
32        }
33    }
34}
35
36impl ToString for Fragment {
37    fn to_string(&self) -> String {
38        format!("#{}", self.0)
39    }
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct Path(String);
44
45impl FromStr for Path {
46    type Err = InvalidPath;
47
48    fn from_str(s: &str) -> Result<Self, Self::Err> {
49        if s.chars().any(char::is_whitespace) {
50            Err(InvalidPath)
51        } else {
52            Ok(Path(s.to_string()))
53        }
54    }
55}
56
57impl ToString for Path {
58    fn to_string(&self) -> String {
59        self.0.clone()
60    }
61}
62
63impl<'de> Deserialize<'de> for SchemaId {
64    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
65    where
66        D: Deserializer<'de>,
67    {
68        deserializer.deserialize_str(SchemaIdVisitor)
69    }
70}
71
72struct SchemaIdVisitor;
73
74impl<'de> Visitor<'de> for SchemaIdVisitor {
75    type Value = SchemaId;
76
77    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
78        write!(
79            formatter,
80            "a string that is either a Url, JsonPointer or Path"
81        )
82    }
83
84    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
85    where
86        E: de::Error,
87    {
88        Fragment::from_str(s)
89            .map(SchemaId::Fragment)
90            .or_else(|_| Url::parse(s).map(SchemaId::Url))
91            .or_else(|_| JsonPointer::from_str(s).map(SchemaId::Pointer))
92            .or_else(|_| Path::from_str(s).map(SchemaId::Path))
93            .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(s), &self))
94    }
95}
96
97impl ToString for SchemaId {
98    fn to_string(&self) -> String {
99        match self {
100            Self::Pointer(p) => p.to_string(),
101            Self::Url(u) => u.to_string(),
102            Self::Fragment(f) => f.to_string(),
103            Self::Path(p) => p.to_string(),
104        }
105    }
106}
107
108impl Serialize for SchemaId {
109    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110    where
111        S: Serializer,
112    {
113        serializer.serialize_str(&self.to_string())
114    }
115}