Skip to main content

vld/primitives/
enumeration.rs

1use serde_json::Value;
2
3use crate::error::{IssueCode, VldError};
4use crate::schema::VldSchema;
5
6/// Schema for string enum validation. Created via [`vld::enumeration()`](crate::enumeration).
7///
8/// # Example
9/// ```
10/// use vld::prelude::*;
11///
12/// let role = vld::enumeration(&["admin", "user", "moderator"]);
13/// assert!(role.parse(r#""admin""#).is_ok());
14/// assert!(role.parse(r#""hacker""#).is_err());
15/// ```
16#[derive(Clone)]
17pub struct ZEnum {
18    variants: Vec<String>,
19    custom_type_error: Option<String>,
20}
21
22impl ZEnum {
23    /// Create the schema (the same as its `vld::` constructor function).
24    pub fn new(variants: &[&str]) -> Self {
25        Self {
26            variants: variants.iter().map(|s| s.to_string()).collect(),
27            custom_type_error: None,
28        }
29    }
30
31    /// Create from a Vec of Strings.
32    pub fn from_strings(variants: Vec<String>) -> Self {
33        Self {
34            variants,
35            custom_type_error: None,
36        }
37    }
38
39    /// Set a custom error message for type mismatch (non-string input).
40    pub fn type_error(mut self, msg: impl Into<String>) -> Self {
41        self.custom_type_error = Some(msg.into());
42        self
43    }
44}
45
46impl VldSchema for ZEnum {
47    type Output = String;
48
49    fn parse_value(&self, value: &Value) -> Result<String, VldError> {
50        let s = value.as_str().ok_or_else(|| {
51            crate::primitives::type_error(&self.custom_type_error, "string", value)
52        })?;
53
54        if self.variants.iter().any(|v| v == s) {
55            Ok(s.to_string())
56        } else {
57            Err(VldError::from_code_with_value(
58                IssueCode::InvalidEnumValue {
59                    options: self.variants.clone(),
60                },
61                value,
62            ))
63        }
64    }
65}
66
67/// Generate a JSON Schema representation.
68#[cfg(feature = "openapi")]
69impl crate::openapi::JsonSchema for ZEnum {
70    fn json_schema(&self) -> serde_json::Value {
71        serde_json::json!({"type": "string", "enum": self.variants})
72    }
73}
74
75#[cfg(feature = "openapi")]
76impl crate::openapi::CollectNestedSchemas for ZEnum {}