Skip to main content
Glama
generic.rs3.52 kB
use std::fmt::Debug; use serde::{ Deserialize, Serialize, }; use crate::require; #[derive(Debug, Clone, Deserialize, Default)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct Validator<T, ExtraFlags> { // Flags that affect rules (such as "only" and "presence") #[serde(default)] pub flags: Flags<ExtraFlags>, // Allowed values (only checked if flags.only is set) pub allow: Option<Vec<T>>, // Disallowed values pub invalid: Option<Vec<T>>, // Preferences like whether to convert values // pub preferences: Option<Preferences>, // Descriptive stuff that's OK to pass through pub examples: Option<Vec<T>>, pub metas: Option<Vec<serde_json::Value>>, pub notes: Option<Vec<String>>, pub tags: Option<Vec<String>>, } impl<T: PartialEq + Serialize + Debug, ExtraFlags> Validator<T, ExtraFlags> { pub fn validate_value(&self, value: &T) -> Result<(), (String, String)> { self.validate_valid_values(value) } pub fn validate_presence<V>(&self, value: &Option<V>) -> Result<(), (String, String)> { match self.flags.presence { Some(Presence::Required) => require(value.is_some(), "any.required", "is required"), Some(Presence::Forbidden) => require(value.is_none(), "any.unknown", "is not allowed"), Some(Presence::Optional) | None => Ok(()), } } fn validate_valid_values(&self, value: &T) -> Result<(), (String, String)> { // Check if it's one of the allowed values if self.flags.only { if let Some(allow) = &self.allow { require( allow.contains(value), "any.only", format!("must be one of {:?}", self.allow), )?; } } // Check for invalid values if let Some(invalid) = &self.invalid { require( !invalid.contains(value), "any.invalid", "contains an invalid value", )?; } Ok(()) } pub fn rule_names(&self) -> Vec<&'static str> { let mut rule_names = vec![]; match self.flags.presence { Some(Presence::Required) => rule_names.push("any.required"), Some(Presence::Forbidden) => rule_names.push("any.unknown"), Some(Presence::Optional) | None => (), } if self.flags.only { if let Some(_allow) = &self.allow { rule_names.push("any.only"); } } if let Some(_invalid) = &self.invalid { rule_names.push("any.invalid"); } rule_names } } #[derive(Debug, Clone, Deserialize, Default)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct Flags<ExtraFlags> { #[serde(default)] pub only: bool, // Defaults to false pub presence: Option<Presence>, // pub unit: Option<String>, // Label to use in error messages pub label: Option<String>, // Purely descriptive pub description: Option<String>, #[serde(flatten)] pub extra_flags: ExtraFlags, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub enum Presence { Forbidden, Optional, Required, } // #[derive(Debug, Clone, Deserialize)] // #[serde(rename_all = "camelCase")] // #[serde(deny_unknown_fields)] // pub struct Preferences { // pub convert: Option<bool>, // }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server