use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FieldCase {
SnakeCase,
CamelCase,
PascalCase,
ScreamingSnakeCase,
KebabCase,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CodeCase {
Default,
ScreamingSnakeCase,
CamelCase,
PascalCase,
KebabCase,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FormatConfig {
pub field_case: FieldCase,
pub code_case: CodeCase,
}
impl Default for FormatConfig {
fn default() -> Self {
Self {
field_case: FieldCase::SnakeCase,
code_case: CodeCase::Default,
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FieldMetadata {
pub rust_name: &'static str,
pub output_name: &'static str,
pub snake_case: &'static str,
pub camel_case: &'static str,
pub pascal_case: &'static str,
pub screaming_snake_case: &'static str,
pub kebab_case: &'static str,
pub ty: &'static str,
pub is_extension: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub http_header: Option<&'static str>,
}
impl FieldMetadata {
pub fn name_for(&self, case: FieldCase) -> &'static str {
match case {
FieldCase::SnakeCase => self.snake_case,
FieldCase::CamelCase => self.camel_case,
FieldCase::PascalCase => self.pascal_case,
FieldCase::ScreamingSnakeCase => self.screaming_snake_case,
FieldCase::KebabCase => self.kebab_case,
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CodeMetadata {
pub default: &'static str,
pub screaming_snake: &'static str,
pub camel: &'static str,
pub pascal: &'static str,
pub kebab: &'static str,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RegularVariantMetadata {
pub name: &'static str,
pub message: &'static str,
pub code: &'static str,
pub code_screaming_snake: &'static str,
pub code_camel: &'static str,
pub code_pascal: &'static str,
pub code_kebab: &'static str,
pub http_status: u16,
pub jsonrpc_code: i32,
#[serde(skip_serializing_if = "Option::is_none")]
pub help: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub severity: Option<&'static str>,
pub fields: &'static [FieldMetadata],
}
impl RegularVariantMetadata {
pub fn code_for(&self, case: CodeCase) -> &'static str {
match case {
CodeCase::Default => self.code,
CodeCase::ScreamingSnakeCase => self.code_screaming_snake,
CodeCase::CamelCase => self.code_camel,
CodeCase::PascalCase => self.code_pascal,
CodeCase::KebabCase => self.code_kebab,
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TransparentVariantMetadata {
pub name: &'static str,
pub forward_to: &'static str,
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum VariantMetadata {
Regular(RegularVariantMetadata),
Transparent(TransparentVariantMetadata),
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ErrorMetadata {
pub type_name: &'static str,
pub variants: &'static [VariantMetadata],
}
#[cfg(test)]
mod tests {
use super::{
CodeCase, ErrorMetadata, FieldCase, FieldMetadata, RegularVariantMetadata, VariantMetadata,
};
#[test]
fn test_serialize_error_metadata() {
static FIELDS: &[FieldMetadata] = &[];
static VARIANTS: &[VariantMetadata] = &[VariantMetadata::Regular(RegularVariantMetadata {
name: "TestVariant",
message: "test message",
code: "test::code",
code_screaming_snake: "TEST_CODE",
code_camel: "testCode",
code_pascal: "TestCode",
code_kebab: "test-code",
http_status: 200,
jsonrpc_code: -32000,
help: None,
url: None,
severity: None,
fields: FIELDS,
})];
let metadata = ErrorMetadata {
type_name: "TestError",
variants: VARIANTS,
};
let json = serde_json::to_value(&metadata).unwrap();
assert_eq!(json["typeName"], "TestError");
let variants_json = json["variants"].as_array().unwrap();
assert_eq!(variants_json.len(), 1);
assert_eq!(variants_json[0]["name"], "TestVariant");
assert_eq!(variants_json[0]["code"], "test::code");
}
#[test]
fn test_field_metadata_name_for() {
let field_metadata = FieldMetadata {
rust_name: "my_field",
output_name: "my_field",
snake_case: "my_field",
camel_case: "myField",
pascal_case: "MyField",
screaming_snake_case: "MY_FIELD",
kebab_case: "my-field",
ty: "String",
is_extension: false,
http_header: None,
};
assert_eq!(field_metadata.name_for(FieldCase::SnakeCase), "my_field");
assert_eq!(field_metadata.name_for(FieldCase::CamelCase), "myField");
assert_eq!(field_metadata.name_for(FieldCase::PascalCase), "MyField");
assert_eq!(
field_metadata.name_for(FieldCase::ScreamingSnakeCase),
"MY_FIELD"
);
assert_eq!(field_metadata.name_for(FieldCase::KebabCase), "my-field");
}
#[test]
fn test_field_metadata_name_for_with_rename() {
let field = FieldMetadata {
rust_name: "my_field",
output_name: "myRenamedField",
snake_case: "my_renamed_field",
camel_case: "myRenamedField",
pascal_case: "MyRenamedField",
screaming_snake_case: "MY_RENAMED_FIELD",
kebab_case: "my-renamed-field",
ty: "String",
is_extension: true,
http_header: None,
};
assert_eq!(field.name_for(FieldCase::SnakeCase), "my_renamed_field");
assert_eq!(field.name_for(FieldCase::CamelCase), "myRenamedField");
assert_eq!(field.name_for(FieldCase::PascalCase), "MyRenamedField");
assert_eq!(
field.name_for(FieldCase::ScreamingSnakeCase),
"MY_RENAMED_FIELD"
);
assert_eq!(field.name_for(FieldCase::KebabCase), "my-renamed-field");
}
#[test]
fn test_regular_variant_metadata_code_for() {
let regular_variant_metadata = RegularVariantMetadata {
name: "MyError",
message: "My error message",
code: "my_error",
code_screaming_snake: "MY_ERROR",
code_camel: "myError",
code_pascal: "MyError",
code_kebab: "my-error",
http_status: 500,
jsonrpc_code: 1000,
help: None,
url: None,
severity: None,
fields: &[],
};
assert_eq!(
regular_variant_metadata.code_for(CodeCase::Default),
"my_error"
);
assert_eq!(
regular_variant_metadata.code_for(CodeCase::ScreamingSnakeCase),
"MY_ERROR"
);
assert_eq!(
regular_variant_metadata.code_for(CodeCase::CamelCase),
"myError"
);
assert_eq!(
regular_variant_metadata.code_for(CodeCase::PascalCase),
"MyError"
);
assert_eq!(
regular_variant_metadata.code_for(CodeCase::KebabCase),
"my-error"
);
}
}