konduto/types/vehicle/
vehicle_type.rs

1use crate::types::validation_errors::ValidationError;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5/// Tipo de veículo
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub enum VehicleType {
8    /// Carro
9    Car,
10    /// Ônibus
11    Bus,
12    /// Caminhão
13    Truck,
14    /// Motocicleta
15    Motorcycle,
16    /// Aeronave
17    Aircraft,
18    /// Barco
19    Boat,
20    /// Bicicleta
21    Bicycle,
22    /// Outro tipo
23    Other(String),
24}
25
26impl VehicleType {
27    const MAX_LENGTH: usize = 15;
28
29    /// Cria um tipo de veículo a partir de uma string
30    pub fn new(value: impl Into<String>) -> Result<Self, ValidationError> {
31        let input = value.into();
32        let trimmed = input.trim().to_lowercase();
33
34        if trimmed.is_empty() {
35            return Err(ValidationError::EmptyField("vehicle_type".to_string()));
36        }
37
38        if trimmed.len() > Self::MAX_LENGTH {
39            return Err(ValidationError::TooLong {
40                field: "vehicle_type".to_string(),
41                max: Self::MAX_LENGTH,
42                actual: trimmed.len(),
43            });
44        }
45
46        Ok(match trimmed.as_str() {
47            "car" => Self::Car,
48            "bus" => Self::Bus,
49            "truck" => Self::Truck,
50            "motorcycle" => Self::Motorcycle,
51            "aircraft" => Self::Aircraft,
52            "boat" => Self::Boat,
53            "bicycle" => Self::Bicycle,
54            other => Self::Other(other.to_string()),
55        })
56    }
57
58    pub fn as_str(&self) -> &str {
59        match self {
60            Self::Car => "car",
61            Self::Bus => "bus",
62            Self::Truck => "truck",
63            Self::Motorcycle => "motorcycle",
64            Self::Aircraft => "aircraft",
65            Self::Boat => "boat",
66            Self::Bicycle => "bicycle",
67            Self::Other(s) => s,
68        }
69    }
70}
71
72impl fmt::Display for VehicleType {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{}", self.as_str())
75    }
76}
77
78impl Serialize for VehicleType {
79    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: serde::Serializer,
82    {
83        serializer.serialize_str(self.as_str())
84    }
85}
86
87impl<'de> Deserialize<'de> for VehicleType {
88    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89    where
90        D: serde::Deserializer<'de>,
91    {
92        let s = String::deserialize(deserializer)?;
93        VehicleType::new(s).map_err(serde::de::Error::custom)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_vehicle_type_from_str() {
103        assert_eq!(VehicleType::new("car").unwrap(), VehicleType::Car);
104        assert_eq!(VehicleType::new("Bus").unwrap(), VehicleType::Bus);
105        assert_eq!(VehicleType::new("TRUCK").unwrap(), VehicleType::Truck);
106    }
107
108    #[test]
109    fn test_vehicle_type_other() {
110        let custom = VehicleType::new("scooter").unwrap();
111        assert_eq!(custom.as_str(), "scooter");
112    }
113
114    #[test]
115    fn test_vehicle_type_serialization() {
116        let car = VehicleType::Car;
117        let json = serde_json::to_string(&car).unwrap();
118        assert_eq!(json, r#""car""#);
119    }
120}
121