Skip to main content

opentalk_types_common/users/
language.rs

1// SPDX-FileCopyrightText: OpenTalk GmbH <mail@opentalk.eu>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5use icu_locid::{LanguageIdentifier, langid};
6
7use crate::utils::ExampleData;
8
9/// A language identifier
10#[derive(
11    Default,
12    Debug,
13    Clone,
14    PartialEq,
15    Eq,
16    Hash,
17    derive_more::Display,
18    derive_more::FromStr,
19    derive_more::From,
20    derive_more::Into,
21    derive_more::AsRef,
22    derive_more::AsMut,
23)]
24#[cfg_attr(
25    feature = "serde",
26    derive(serde::Serialize, serde_with::DeserializeFromStr)
27)]
28pub struct Language(pub LanguageIdentifier);
29
30impl Language {
31    /// Create a new empty [`Language`]
32    pub fn new() -> Self {
33        Self::default()
34    }
35}
36
37#[cfg(feature = "utoipa")]
38mod impl_to_schema {
39    //! The `#[derive(utoipa::ToSchema)] implementation does not yet properly support
40    //! exposing schema information of types wrapped by the NewType pattern, therefore
41    //! a manual implementation is required for now.
42    //! Issue: <https://github.com/juhaku/utoipa/issues/663>
43
44    use serde_json::json;
45    use utoipa::{
46        PartialSchema, ToSchema,
47        openapi::{ObjectBuilder, RefOr, Schema, Type},
48    };
49
50    use super::Language;
51    use crate::utils::ExampleData as _;
52
53    impl PartialSchema for Language {
54        fn schema() -> RefOr<Schema> {
55            ObjectBuilder::new()
56                .schema_type(Type::String)
57                .description(Some("A language identifier"))
58                .format(Some(utoipa::openapi::SchemaFormat::Custom(
59                    "bcp-47".to_string(),
60                )))
61                .examples([json!(Language::example_data())])
62                .into()
63        }
64    }
65
66    impl ToSchema for Language {
67        fn schemas(schemas: &mut Vec<(String, RefOr<Schema>)>) {
68            schemas.push((Self::name().into(), Self::schema()));
69        }
70    }
71}
72
73impl ExampleData for Language {
74    fn example_data() -> Self {
75        Self(langid!("de"))
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use icu_locid::langid;
82    use pretty_assertions::assert_eq;
83
84    use super::Language;
85
86    #[test]
87    fn parse() {
88        assert_eq!(
89            "de-AT".parse::<Language>().unwrap(),
90            Language(langid!("de-AT"))
91        );
92        assert_eq!("xx".parse::<Language>().unwrap(), Language(langid!("xx")));
93    }
94
95    #[test]
96    fn parse_invalid() {
97        assert!("".parse::<Language>().is_err());
98        assert!("🚀".parse::<Language>().is_err());
99    }
100}