1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-29 22:01:14 +03:00

iana: manually implement JsonSchema/Display/FromStr/Serialize/Deserialize

This removes the dependency on serde_with and parse-display, and makes
the serde & schemars dependencies optional
This commit is contained in:
Quentin Gliech
2023-02-01 14:20:45 +01:00
parent 792d3c793b
commit 311cad47c2
8 changed files with 2424 additions and 610 deletions

View File

@ -0,0 +1,261 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::traits::{EnumMember, Section};
pub fn struct_def(
f: &mut std::fmt::Formatter<'_>,
section: &Section,
list: &[EnumMember],
is_exhaustive: bool,
) -> std::fmt::Result {
write!(
f,
r#"/// {}
///
/// Source: <{}>
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]"#,
section.doc,
section.url.unwrap(),
)?;
if !is_exhaustive {
write!(
f,
r#"
#[non_exhaustive]"#
)?;
}
write!(
f,
r#"
pub enum {} {{"#,
section.key,
)?;
for member in list {
writeln!(f)?;
if let Some(description) = &member.description {
writeln!(f, " /// {description}")?;
} else {
writeln!(f, " /// `{}`", member.value)?;
}
writeln!(f, " {},", member.enum_name)?;
}
if !is_exhaustive {
// Add a variant for custom enums
writeln!(f)?;
writeln!(f, " /// An unknown value.")?;
writeln!(f, " Unknown(String),")?;
}
writeln!(f, "}}")
}
pub fn display_impl(
f: &mut std::fmt::Formatter<'_>,
section: &Section,
list: &[EnumMember],
is_exhaustive: bool,
) -> std::fmt::Result {
write!(
f,
r#"impl core::fmt::Display for {} {{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {{
match self {{"#,
section.key,
)?;
for member in list {
write!(
f,
r#"
Self::{} => write!(f, "{}"),"#,
member.enum_name, member.value
)?;
}
if !is_exhaustive {
write!(
f,
r#"
Self::Unknown(value) => write!(f, "{{value}}"),"#
)?;
}
writeln!(
f,
r#"
}}
}}
}}"#,
)
}
pub fn from_str_impl(
f: &mut std::fmt::Formatter<'_>,
section: &Section,
list: &[EnumMember],
is_exhaustive: bool,
) -> std::fmt::Result {
let err_ty = if is_exhaustive {
"crate::ParseError"
} else {
"core::convert::Infallible"
};
write!(
f,
r#"impl core::str::FromStr for {} {{
type Err = {err_ty};
fn from_str(s: &str) -> Result<Self, Self::Err> {{
match s {{"#,
section.key,
)?;
for member in list {
write!(
f,
r#"
"{}" => Ok(Self::{}),"#,
member.value, member.enum_name
)?;
}
if is_exhaustive {
write!(
f,
r#"
_ => Err(crate::ParseError::new()),"#
)?;
} else {
write!(
f,
r#"
value => Ok(Self::Unknown(value.to_owned())),"#,
)?;
}
writeln!(
f,
r#"
}}
}}
}}"#,
)
}
pub fn json_schema_impl(
f: &mut std::fmt::Formatter<'_>,
section: &Section,
list: &[EnumMember],
) -> std::fmt::Result {
write!(
f,
r#"#[cfg(feature = "schemars")]
impl schemars::JsonSchema for {} {{
fn schema_name() -> String {{
"{}".to_owned()
}}
#[allow(clippy::too_many_lines)]
fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {{
let enums = vec!["#,
section.key, section.key,
)?;
for member in list {
write!(
f,
r#"
// ---
schemars::schema::SchemaObject {{"#,
)?;
if let Some(description) = &member.description {
write!(
f,
r##"
metadata: Some(Box::new(schemars::schema::Metadata {{
description: Some(
// ---
r#"{description}"#.to_owned(),
),
..Default::default()
}})),"##,
)?;
}
write!(
f,
r#"
const_value: Some("{}".into()),
..Default::default()
}}
.into(),"#,
member.value
)?;
}
writeln!(
f,
r##"
];
let description = r#"{}"#;
schemars::schema::SchemaObject {{
metadata: Some(Box::new(schemars::schema::Metadata {{
description: Some(description.to_owned()),
..Default::default()
}})),
subschemas: Some(Box::new(schemars::schema::SubschemaValidation {{
any_of: Some(enums),
..Default::default()
}})),
..Default::default()
}}
.into()
}}
}}"##,
section.doc,
)
}
pub fn serde_impl(f: &mut std::fmt::Formatter<'_>, section: &Section) -> std::fmt::Result {
writeln!(
f,
r#"#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for {} {{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{{
let s = String::deserialize(deserializer)?;
core::str::FromStr::from_str(&s).map_err(serde::de::Error::custom)
}}
}}
#[cfg(feature = "serde")]
impl serde::Serialize for {} {{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{{
serializer.serialize_str(&self.to_string())
}}
}}"#,
section.key, section.key,
)
}

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
// Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ use reqwest::Client;
use tokio::io::AsyncWriteExt;
use tracing::Level;
mod gen;
pub mod jose;
pub mod oauth;
pub mod traits;
@ -82,10 +83,11 @@ impl File {
}
impl Display for File {
#[allow(clippy::too_many_lines)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
r#"// Copyright 2022 The Matrix.org Foundation C.I.C.
r#"// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -102,11 +104,7 @@ impl Display for File {
//! Enums from the {:?} IANA registry
//! See <{}>
// Do not edit this file manually
use parse_display::{{Display, FromStr}};
use schemars::JsonSchema;
use serde_with::{{DeserializeFromStr, SerializeDisplay}};"#,
// Do not edit this file manually"#,
self.registry_name, self.registry_url,
)?;
@ -116,61 +114,25 @@ use serde_with::{{DeserializeFromStr, SerializeDisplay}};"#,
};
let is_exhaustive = section.key == "OAuthAuthorizationEndpointResponseType";
writeln!(f)?;
let non_exhaustive_attr = if is_exhaustive {
""
} else {
"\n#[non_exhaustive]"
};
self::gen::struct_def(f, section, list, is_exhaustive)?;
writeln!(f)?;
write!(
f,
r#"
/// {}
///
/// Source: <{}>
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
FromStr,
SerializeDisplay,
DeserializeFromStr,
JsonSchema,
)]{}
pub enum {} {{"#,
section.doc,
section.url.unwrap(),
non_exhaustive_attr,
section.key,
)?;
for member in list {
writeln!(f)?;
if let Some(description) = &member.description {
writeln!(f, " /// {description}")?;
} else {
writeln!(f, " /// `{}`", member.value)?;
}
writeln!(f, " #[schemars(rename = \"{}\")]", member.value)?;
writeln!(f, " #[display(\"{}\")]", member.value)?;
writeln!(f, " {},", member.enum_name)?;
}
// Write the Display impl
self::gen::display_impl(f, section, list, is_exhaustive)?;
writeln!(f)?;
if !is_exhaustive {
// Add a variant for custom enums
writeln!(f)?;
writeln!(f, " /// An unknown value.")?;
writeln!(f, " #[display(\"{{0}}\")]")?;
writeln!(f, " #[schemars(skip)]")?;
writeln!(f, " Unknown(String),")?;
}
// Write the FromStr impl
self::gen::from_str_impl(f, section, list, is_exhaustive)?;
writeln!(f)?;
writeln!(f, "}}")?;
// Write the Serialize and Deserialize impls
self::gen::serde_impl(f, section)?;
writeln!(f)?;
// Write the JsonSchema impl
self::gen::json_schema_impl(f, section, list)?;
}
Ok(())