1use crate::{LanguageIdentifier, Locale};
6use core::{fmt::Display, marker::PhantomData, str::FromStr};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use writeable::Writeable;
9
10impl Serialize for LanguageIdentifier {
11 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
12 where
13 S: Serializer,
14 {
15 serializer.serialize_str(&self.write_to_string())
16 }
17}
18
19impl Serialize for Locale {
20 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21 where
22 S: Serializer,
23 {
24 serializer.serialize_str(&self.write_to_string())
25 }
26}
27
28struct ParseVisitor<T>(PhantomData<T>);
29
30impl<T> serde::de::Visitor<'_> for ParseVisitor<T>
31where
32 T: FromStr,
33 <T as FromStr>::Err: Display,
34{
35 type Value = T;
36
37 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38 write!(formatter, "a valid Unicode Language or Locale Identifier")
39 }
40
41 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
42 where
43 E: serde::de::Error,
44 {
45 s.parse::<T>().map_err(serde::de::Error::custom)
46 }
47}
48
49impl<'de> Deserialize<'de> for LanguageIdentifier {
50 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51 where
52 D: Deserializer<'de>,
53 {
54 deserializer.deserialize_str(ParseVisitor(PhantomData))
55 }
56}
57
58impl<'de> Deserialize<'de> for Locale {
59 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60 where
61 D: Deserializer<'de>,
62 {
63 deserializer.deserialize_str(ParseVisitor(PhantomData))
64 }
65}
66
67#[test]
68fn json() {
69 use crate::subtags::{Language, Region, Script};
70 use crate::{langid, locale};
71
72 assert_eq!(
73 serde_json::to_string(&langid!("en-US")).unwrap(),
74 r#""en-US""#
75 );
76 assert_eq!(
77 serde_json::from_str::<LanguageIdentifier>(r#""en-US""#).unwrap(),
78 langid!("en-US")
79 );
80 assert_eq!(
81 serde_json::from_reader::<_, LanguageIdentifier>(&br#""en-US""#[..]).unwrap(),
82 langid!("en-US")
83 );
84 assert!(serde_json::from_str::<LanguageIdentifier>(r#""2Xs""#).is_err());
85
86 assert_eq!(
87 serde_json::to_string(&locale!("en-US-u-hc-h12")).unwrap(),
88 r#""en-US-u-hc-h12""#
89 );
90 assert_eq!(
91 serde_json::from_str::<Locale>(r#""en-US-u-hc-h12""#).unwrap(),
92 locale!("en-US-u-hc-h12")
93 );
94 assert_eq!(
95 serde_json::from_reader::<_, Locale>(&br#""en-US-u-hc-h12""#[..]).unwrap(),
96 locale!("en-US-u-hc-h12")
97 );
98 assert!(serde_json::from_str::<Locale>(r#""2Xs""#).is_err());
99
100 assert_eq!(
101 serde_json::to_string(&"fr".parse::<Language>().unwrap()).unwrap(),
102 r#""fr""#
103 );
104 assert_eq!(
105 serde_json::from_str::<Language>(r#""fr""#).unwrap(),
106 "fr".parse::<Language>().unwrap()
107 );
108 assert_eq!(
109 serde_json::from_reader::<_, Language>(&br#""fr""#[..]).unwrap(),
110 "fr".parse::<Language>().unwrap()
111 );
112 assert!(serde_json::from_str::<Language>(r#""2Xs""#).is_err());
113
114 assert_eq!(
115 serde_json::to_string(&"Latn".parse::<Script>().unwrap()).unwrap(),
116 r#""Latn""#
117 );
118 assert_eq!(
119 serde_json::from_str::<Script>(r#""Latn""#).unwrap(),
120 "Latn".parse::<Script>().unwrap()
121 );
122 assert_eq!(
123 serde_json::from_reader::<_, Script>(&br#""Latn""#[..]).unwrap(),
124 "Latn".parse::<Script>().unwrap()
125 );
126 assert!(serde_json::from_str::<Script>(r#""2Xs""#).is_err());
127
128 assert_eq!(
129 serde_json::to_string(&"US".parse::<Region>().unwrap()).unwrap(),
130 r#""US""#
131 );
132 assert_eq!(
133 serde_json::from_str::<Region>(r#""US""#).unwrap(),
134 "US".parse::<Region>().unwrap()
135 );
136 assert_eq!(
137 serde_json::from_reader::<_, Region>(&br#""US""#[..]).unwrap(),
138 "US".parse::<Region>().unwrap()
139 );
140 assert!(serde_json::from_str::<Region>(r#""2Xs""#).is_err());
141}
142
143#[test]
144fn postcard() {
145 use crate::subtags::{Language, Region, Script};
146 use crate::{langid, locale};
147
148 assert_eq!(
149 postcard::to_stdvec(&langid!("en-US")).unwrap(),
150 b"\x05en-US"
151 );
152 assert_eq!(
153 postcard::from_bytes::<LanguageIdentifier>(b"\x05en-US").unwrap(),
154 langid!("en-US")
155 );
156 assert!(postcard::from_bytes::<LanguageIdentifier>(b"\x032Xs").is_err());
157
158 assert_eq!(
159 postcard::to_stdvec(&locale!("en-US-u-hc-h12")).unwrap(),
160 b"\x0Een-US-u-hc-h12"
161 );
162 assert_eq!(
163 postcard::from_bytes::<Locale>(b"\x0Een-US-u-hc-h12").unwrap(),
164 locale!("en-US-u-hc-h12")
165 );
166 assert!(postcard::from_bytes::<Locale>(b"\x032Xs").is_err());
167
168 assert_eq!(
169 postcard::to_stdvec(&"fr".parse::<Language>().unwrap()).unwrap(),
170 b"fr\0"
171 );
172 assert_eq!(
173 postcard::from_bytes::<Language>(b"fr\0").unwrap(),
174 "fr".parse::<Language>().unwrap()
175 );
176 assert!(postcard::from_bytes::<Language>(b"2Xs").is_err());
177
178 assert_eq!(
179 postcard::to_stdvec(&"Latn".parse::<Script>().unwrap()).unwrap(),
180 b"Latn"
181 );
182 assert_eq!(
183 postcard::from_bytes::<Script>(b"Latn").unwrap(),
184 "Latn".parse::<Script>().unwrap()
185 );
186 assert!(postcard::from_bytes::<Script>(b"2Xss").is_err());
187
188 assert_eq!(
189 postcard::to_stdvec(&"US".parse::<Region>().unwrap()).unwrap(),
190 b"US\0"
191 );
192 assert_eq!(
193 postcard::from_bytes::<Region>(b"US\0").unwrap(),
194 "US".parse::<Region>().unwrap()
195 );
196 assert!(postcard::from_bytes::<Region>(b"2Xs").is_err());
197}