json_api/value/fields/
key.rs

1use std::borrow::Borrow;
2use std::fmt::{self, Display, Formatter};
3use std::ops::Deref;
4use std::str::FromStr;
5
6use serde::de::{self, Deserialize, Deserializer, Visitor};
7use serde::ser::{Serialize, Serializer};
8
9use error::Error;
10use sealed::Sealed;
11use value::Stringify;
12
13/// Represents a single member name.
14///
15/// When a new `Key` is parsed, the underlying value's casing convention is converted to
16/// kebab-case.
17///
18/// # Example
19///
20/// ```
21/// # extern crate json_api;
22/// #
23/// # use std::str::FromStr;
24/// #
25/// # use json_api::Error;
26/// # use json_api::value::Key;
27/// #
28/// # fn example() -> Result<(), Error> {
29/// let key = Key::from_str("someFieldName")?;
30/// assert_eq!(key, "some-field-name");
31/// #
32/// # Ok(())
33/// # }
34/// #
35/// # fn main() {
36/// # example().unwrap()
37/// # }
38/// ```
39#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
40pub struct Key(String);
41
42impl Key {
43    #[doc(hidden)]
44    #[inline]
45    pub fn from_raw(value: String) -> Self {
46        Key(value)
47    }
48}
49
50impl AsRef<[u8]> for Key {
51    fn as_ref(&self) -> &[u8] {
52        self.as_bytes()
53    }
54}
55
56impl AsRef<str> for Key {
57    fn as_ref(&self) -> &str {
58        self
59    }
60}
61
62impl Borrow<str> for Key {
63    fn borrow(&self) -> &str {
64        self
65    }
66}
67
68impl Deref for Key {
69    type Target = str;
70
71    fn deref(&self) -> &Self::Target {
72        self.0.as_str()
73    }
74}
75
76impl Display for Key {
77    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
78        f.write_str(self)
79    }
80}
81
82impl From<Key> for String {
83    fn from(key: Key) -> Self {
84        let Key(value) = key;
85        value
86    }
87}
88
89impl FromStr for Key {
90    type Err = Error;
91
92    fn from_str(source: &str) -> Result<Key, Self::Err> {
93        if source.is_empty() {
94            bail!("cannot be blank");
95        }
96
97        // We should reserve a bit more than what we need so in
98        // the event that we end up converting camelCase to
99        // kebab-case, we don't have to reallocate.
100        let mut dest = String::with_capacity(source.len() + 10);
101        let mut chars = source.chars().peekable();
102
103        while let Some(value) = chars.next() {
104            match value {
105                '\u{002e}' |
106                '\u{002f}' |
107                '\u{0040}' |
108                '\u{0060}' |
109                '\u{0000}'...'\u{001f}' |
110                '\u{0021}'...'\u{0029}' |
111                '\u{002a}'...'\u{002c}' |
112                '\u{003a}'...'\u{003f}' |
113                '\u{005b}'...'\u{005e}' |
114                '\u{007b}'...'\u{007f}' => {
115                    bail!("reserved '{}'", value);
116                }
117                '_' | '-' | ' ' if dest.is_empty() => {
118                    bail!("cannot start with '{}'", value);
119                }
120                '_' | '-' | ' ' => match chars.peek() {
121                    Some(&'-') | Some(&'_') | Some(&' ') | Some(&'A'...'Z') => {
122                        continue;
123                    }
124                    Some(_) => {
125                        dest.push('-');
126                    }
127                    None => {
128                        bail!("cannot end with '{}'", value);
129                    }
130                },
131                'A'...'Z' if dest.ends_with('-') => {
132                    dest.push(as_lowercase(value));
133                }
134                'A'...'Z' => {
135                    dest.push('-');
136                    dest.push(as_lowercase(value));
137                }
138                _ => {
139                    dest.push(value);
140                }
141            }
142        }
143
144        Ok(Key(dest))
145    }
146}
147
148impl PartialEq<String> for Key {
149    fn eq(&self, rhs: &String) -> bool {
150        &self.0 == rhs
151    }
152}
153
154impl PartialEq<str> for Key {
155    fn eq(&self, rhs: &str) -> bool {
156        &**self == rhs
157    }
158}
159
160impl<'a> PartialEq<&'a str> for Key {
161    fn eq(&self, rhs: &&str) -> bool {
162        &**self == *rhs
163    }
164}
165
166impl<'de> Deserialize<'de> for Key {
167    fn deserialize<D>(deserializer: D) -> Result<Key, D::Error>
168    where
169        D: Deserializer<'de>,
170    {
171        struct KeyVisitor;
172
173        impl<'de> Visitor<'de> for KeyVisitor {
174            type Value = Key;
175
176            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
177                f.write_str("a valid json api member name")
178            }
179
180            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
181            where
182                E: de::Error,
183            {
184                value.parse().map_err(de::Error::custom)
185            }
186        }
187
188        deserializer.deserialize_str(KeyVisitor)
189    }
190}
191
192impl Serialize for Key {
193    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194    where
195        S: Serializer,
196    {
197        serializer.serialize_str(self)
198    }
199}
200
201impl Sealed for Key {}
202
203impl Stringify for Key {
204    fn to_bytes(&self) -> Vec<u8> {
205        self.as_bytes().to_vec()
206    }
207}
208
209#[inline]
210fn as_lowercase(value: char) -> char {
211    (value as u8 + 32) as char
212}