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    pub fn new(variants: &[&str]) -> Self {
24        Self {
25            variants: variants.iter().map(|s| s.to_string()).collect(),
26            custom_type_error: None,
27        }
28    }
29
30    /// Create from a Vec of Strings.
31    pub fn from_strings(variants: Vec<String>) -> Self {
32        Self {
33            variants,
34            custom_type_error: None,
35        }
36    }
37
38    /// Set a custom error message for type mismatch (non-string input).
39    pub fn type_error(mut self, msg: impl Into<String>) -> Self {
40        self.custom_type_error = Some(msg.into());
41        self
42    }
43}
44
45impl VldSchema for ZEnum {
46    type Output = String;
47
48    fn parse_value(&self, value: &Value) -> Result<String, VldError> {
49        let s = value.as_str().ok_or_else(|| {
50            crate::primitives::type_error(&self.custom_type_error, "string", value)
51        })?;
52
53        if self.variants.iter().any(|v| v == s) {
54            Ok(s.to_string())
55        } else {
56            Err(VldError::from_code_with_value(
57                IssueCode::InvalidEnumValue {
58                    options: self.variants.clone(),
59                },
60                value,
61            ))
62        }
63    }
64}
65
66/// Generate a JSON Schema representation.
67#[cfg(feature = "openapi")]
68impl crate::openapi::JsonSchema for ZEnum {
69    fn json_schema(&self) -> serde_json::Value {
70        serde_json::json!({"type": "string", "enum": self.variants})
71    }
72}
73
74#[cfg(feature = "openapi")]
75impl crate::openapi::CollectNestedSchemas for ZEnum {}