apache_avro/schema/
name.rs1use crate::{
19 AvroResult, Error, Schema,
20 error::Details,
21 util::{JsonValueDescriber, MapHelper},
22 validator::{validate_namespace, validate_schema_name},
23};
24use serde::{Deserialize, Serialize, Serializer};
25use serde_json::{Map, Value};
26use std::borrow::Cow;
27use std::collections::HashMap;
28use std::fmt::{Debug, Display, Formatter};
29use std::str::FromStr;
30use std::sync::Arc;
31
32#[derive(Clone, Hash, PartialEq, Eq)]
43pub struct Name {
44 namespace_and_name: Arc<str>,
46 index_of_name: usize,
50}
51
52pub type Aliases = Option<Vec<Alias>>;
54pub type Names = HashMap<Name, Schema>;
56pub type NamesRef<'a> = HashMap<Name, &'a Schema>;
58pub type Namespace = Option<String>;
60pub type NamespaceRef<'a> = Option<&'a str>;
62
63impl Name {
64 pub fn new(name: impl Into<String> + AsRef<str>) -> AvroResult<Self> {
68 Self::new_with_enclosing_namespace(name, None)
69 }
70
71 pub fn new_with_enclosing_namespace(
73 name: impl Into<String> + AsRef<str>,
74 enclosing_namespace: NamespaceRef,
75 ) -> AvroResult<Self> {
76 let name_ref = name.as_ref();
83 let index_of_name = validate_schema_name(name_ref)?;
84 if index_of_name > name_ref.len() {
85 return Err(Details::InvalidSchemaNameValidatorImplementation.into());
86 }
87
88 if index_of_name == 0
89 && let Some(namespace) = enclosing_namespace
90 && !namespace.is_empty()
91 {
92 validate_namespace(namespace)?;
93 Ok(Self {
94 namespace_and_name: format!("{namespace}.{name_ref}").into(),
95 index_of_name: namespace.len() + 1,
96 })
97 } else if index_of_name == 1 {
98 Ok(Self {
100 namespace_and_name: name.as_ref()[1..].into(),
101 index_of_name: 0,
102 })
103 } else {
104 Ok(Self {
105 namespace_and_name: Arc::from(name.into()),
106 index_of_name,
107 })
108 }
109 }
110
111 pub(crate) fn parse(
113 complex: &mut Map<String, Value>,
114 enclosing_namespace: NamespaceRef,
115 ) -> AvroResult<Self> {
116 let name_field = complex.name()?;
117 let namespace = match complex.remove("namespace") {
118 Some(Value::String(s)) => Some(s),
119 Some(Value::Null) | None => None,
120 Some(value) => {
121 return Err(Details::GetNamespaceFieldWrongType(value.description()).into());
122 }
123 };
124 Self::new_with_enclosing_namespace(name_field, namespace.as_deref().or(enclosing_namespace))
125 }
126
127 pub fn name(&self) -> &str {
128 &self.namespace_and_name[self.index_of_name..]
129 }
130
131 pub fn namespace(&self) -> NamespaceRef<'_> {
132 if self.index_of_name == 0 {
133 None
134 } else {
135 Some(&self.namespace_and_name[..(self.index_of_name - 1)])
136 }
137 }
138
139 pub fn fullname(&self, enclosing_namespace: NamespaceRef) -> String {
144 if self.index_of_name == 0
145 && let Some(namespace) = enclosing_namespace
146 && !namespace.is_empty()
147 {
148 format!("{namespace}.{}", self.namespace_and_name)
149 } else {
150 self.namespace_and_name.to_string()
151 }
152 }
153
154 pub fn fully_qualified_name(&self, enclosing_namespace: NamespaceRef) -> Cow<'_, Name> {
169 if self.index_of_name == 0
170 && let Some(namespace) = enclosing_namespace
171 && !namespace.is_empty()
172 {
173 Cow::Owned(Self {
174 namespace_and_name: format!("{namespace}.{}", self.namespace_and_name).into(),
175 index_of_name: namespace.len() + 1,
176 })
177 } else {
178 Cow::Borrowed(self)
179 }
180 }
181
182 pub(crate) fn invalid_empty_name() -> Self {
189 Self {
190 namespace_and_name: Arc::default(),
191 index_of_name: usize::MAX,
192 }
193 }
194}
195
196impl TryFrom<&str> for Name {
197 type Error = Error;
198
199 fn try_from(value: &str) -> Result<Self, Self::Error> {
200 Self::new(value)
201 }
202}
203
204impl TryFrom<String> for Name {
205 type Error = Error;
206
207 fn try_from(value: String) -> Result<Self, Self::Error> {
208 Self::new(&value)
209 }
210}
211
212impl FromStr for Name {
213 type Err = Error;
214
215 fn from_str(s: &str) -> Result<Self, Self::Err> {
216 Self::new(s)
217 }
218}
219
220impl Debug for Name {
221 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
222 if self.index_of_name > self.namespace_and_name.len() {
223 f.debug_tuple("Name").field(&"Invalid name!").finish()
224 } else {
225 let mut debug = f.debug_struct("Name");
226 debug.field("name", &self.name());
227 if self.index_of_name != 0 {
228 debug.field("namespace", &self.namespace());
229 debug.finish()
230 } else {
231 debug.finish_non_exhaustive()
232 }
233 }
234 }
235}
236
237impl AsRef<str> for Name {
238 fn as_ref(&self) -> &str {
239 self.namespace_and_name.as_ref()
240 }
241}
242
243impl Display for Name {
244 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
245 assert!(
246 self.index_of_name <= self.namespace_and_name.len(),
247 "Invalid name used"
248 );
249 f.write_str(&self.namespace_and_name)
250 }
251}
252
253impl<'de> Deserialize<'de> for Name {
254 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
255 where
256 D: serde::de::Deserializer<'de>,
257 {
258 Value::deserialize(deserializer).and_then(|value| {
259 use serde::de::Error;
260 if let Value::Object(mut json) = value {
261 Name::parse(&mut json, None).map_err(Error::custom)
262 } else {
263 Err(Error::custom(format!("Expected a JSON object: {value:?}")))
264 }
265 })
266 }
267}
268
269#[derive(Clone, Debug, Hash, PartialEq, Eq)]
273pub struct Alias(Name);
274
275impl Alias {
276 pub fn new(name: impl Into<String> + AsRef<str>) -> AvroResult<Self> {
277 Name::new(name).map(Self)
278 }
279
280 pub fn new_with_enclosing_namespace(
282 name: impl Into<String> + AsRef<str>,
283 enclosing_namespace: NamespaceRef,
284 ) -> AvroResult<Self> {
285 Name::new_with_enclosing_namespace(name, enclosing_namespace).map(Self)
286 }
287
288 pub fn name(&self) -> &str {
289 self.0.name()
290 }
291
292 pub fn namespace(&self) -> NamespaceRef<'_> {
293 self.0.namespace()
294 }
295
296 pub fn fullname(&self, enclosing_namespace: NamespaceRef) -> String {
297 self.0.fullname(enclosing_namespace)
298 }
299
300 pub fn fully_qualified_name(&self, default_namespace: NamespaceRef) -> Cow<'_, Name> {
301 self.0.fully_qualified_name(default_namespace)
302 }
303}
304
305impl TryFrom<&str> for Alias {
306 type Error = Error;
307
308 fn try_from(value: &str) -> Result<Self, Self::Error> {
309 Self::new(value)
310 }
311}
312
313impl TryFrom<String> for Alias {
314 type Error = Error;
315
316 fn try_from(value: String) -> Result<Self, Self::Error> {
317 Self::new(&value)
318 }
319}
320
321impl FromStr for Alias {
322 type Err = Error;
323
324 fn from_str(s: &str) -> Result<Self, Self::Err> {
325 Self::new(s)
326 }
327}
328
329impl Serialize for Alias {
330 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
331 where
332 S: Serializer,
333 {
334 serializer.serialize_str(&self.fullname(None))
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use crate::Error;
341
342 use super::*;
343 use apache_avro_test_helper::TestResult;
344
345 #[test]
346 fn test_namespace_from_name_with_empty_value() -> TestResult {
348 let name = Name::new(".name")?;
349 assert_eq!(name.namespace_and_name.as_ref(), "name");
350 assert_eq!(name.index_of_name, 0);
351
352 Ok(())
353 }
354
355 #[test]
356 fn test_name_with_whitespace_value() {
358 match Name::new(" ").map_err(Error::into_details) {
359 Err(Details::InvalidSchemaName(_, _)) => {}
360 _ => panic!("Expected an Details::InvalidSchemaName!"),
361 }
362 }
363
364 #[test]
365 fn test_name_with_no_name_part() {
367 match Name::new("space.").map_err(Error::into_details) {
368 Err(Details::InvalidSchemaName(_, _)) => {}
369 _ => panic!("Expected an Details::InvalidSchemaName!"),
370 }
371 }
372
373 #[test]
376 fn test_avro_3897_funny_valid_names_and_namespaces() -> TestResult {
377 for funny_name in ["_", "_._", "__._", "_.__", "_._._"] {
378 let name = Name::new(funny_name);
379 assert!(name.is_ok());
380 }
381 Ok(())
382 }
383}