diff --git a/src/register/field_name.rs b/src/register/field_name.rs index 9fede8f..be505aa 100644 --- a/src/register/field_name.rs +++ b/src/register/field_name.rs @@ -1,4 +1,4 @@ -use std::{convert::Infallible, fmt::Display, slice::Iter}; +use std::{convert::Infallible, fmt::Display, hash::Hash, slice::Iter}; use super::{ lexer::{Cursor, Token, TokenKind}, @@ -36,32 +36,83 @@ impl Display for FieldName { } } -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct FieldNames(Vec); +fn names_to_string(vec: &Vec) -> String { + let mut string = String::new(); + for item in vec.iter() { + match item { + FieldName::Literal(s) => { + if !string.is_empty() { + string.push('.'); + } + string.push_str(s); + } + FieldName::Array(n) => { + string.push('['); + string.push_str(&n.to_string()); + string.push(']'); + } + FieldName::Tuple(n) => { + if !string.is_empty() { + string.push('.'); + } + string.push_str(&n.to_string()); + } + FieldName::StructVariant(s) => { + string.push('['); + string.push_str(&s.to_string()); + string.push(']'); + } + } + } + string +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FieldNames { + string: String, + vec: Vec, +} + +impl Hash for FieldNames { + fn hash(&self, state: &mut H) { + self.string.hash(state) + } +} impl FieldNames { pub(crate) fn new() -> Self { - Self(Vec::new()) + Self { + string: String::new(), + vec: Vec::new(), + } } pub fn iter(&self) -> Iter<'_, FieldName> { - self.0.iter() + self.vec.iter() } } impl From> for FieldNames { fn from(value: Vec) -> Self { - Self(value) + Self { + string: names_to_string(&value), + vec: value, + } } } impl From for FieldNames { fn from(value: FieldName) -> Self { - Self(vec![value]) + let vec = vec![value]; + Self { + string: names_to_string(&vec), + vec, + } } } impl From<[FieldName; N]> for FieldNames { fn from(value: [FieldName; N]) -> Self { - Self(value.into_iter().collect()) + let vec: Vec<_> = value.into_iter().collect(); + Self::from(vec) } } @@ -74,38 +125,50 @@ pub trait IntoFieldName { impl IntoFieldName for &str { type Error = String; fn into_field(self) -> Result { - Ok(FieldNames(parse(self)?)) + Ok(FieldNames { + string: self.to_string(), + vec: parse(self)?, + }) } } impl IntoFieldName for u8 { type Error = Infallible; fn into_field(self) -> Result { - Ok(FieldNames(vec![FieldName::Tuple(self)])) + Ok(FieldNames { + string: self.to_string(), + vec: vec![FieldName::Tuple(self)], + }) } } impl IntoFieldName for (u8, u8) { type Error = Infallible; fn into_field(self) -> Result { - Ok(FieldNames(vec![ - FieldName::Tuple(self.0), - FieldName::Tuple(self.1), - ])) + Ok(FieldNames { + string: format!("{}.{}", self.0, self.1), + vec: vec![FieldName::Tuple(self.0), FieldName::Tuple(self.1)], + }) } } impl IntoFieldName for (u8, u8, u8) { type Error = Infallible; fn into_field(self) -> Result { - Ok(FieldNames(vec![ - FieldName::Tuple(self.0), - FieldName::Tuple(self.1), - FieldName::Tuple(self.2), - ])) + Ok(FieldNames { + string: format!("{}.{}.{}", self.0, self.1, self.2), + vec: vec![ + FieldName::Tuple(self.0), + FieldName::Tuple(self.1), + FieldName::Tuple(self.2), + ], + }) } } impl IntoFieldName for [usize; 1] { type Error = Infallible; fn into_field(self) -> Result { - Ok(FieldNames(vec![FieldName::Array(self[0])])) + Ok(FieldNames { + string: format!("[{}]", self[0]), + vec: vec![FieldName::Array(self[0])], + }) } } // impl IntoFieldName for [&str; 1] { @@ -268,14 +331,18 @@ pub fn parse(source: &str) -> Result, String> { } pub fn parse_message(source: &str) -> Result { - let mut names = parse(source)?; - - if let Some(name) = names.pop() { - if let FieldName::Literal(s) = name { - return Ok(MessageKey::new(FieldNames(names), s)); - } - } - Err("not found validate rule name".into()) + let (name, string) = source + .rsplit_once('.') + .ok_or("not found message".to_owned())?; + let mut names = parse(name)?; + + Ok(MessageKey::new( + FieldNames { + string: source.to_string(), + vec: names, + }, + string.to_string(), + )) } #[test] diff --git a/src/register/mod.rs b/src/register/mod.rs index ae21ba5..c406e4f 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -1,6 +1,6 @@ //! register rules -use std::{collections::HashMap, ops::Deref}; +use std::{collections::HashMap, hash::Hash, ops::Deref}; use crate::{ rule::{IntoRuleList, RuleList}, @@ -152,12 +152,19 @@ impl From for Result<(), Response> { } } -#[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct MessageKey { fields: FieldNames, rule: String, } +impl Hash for MessageKey { + fn hash(&self, state: &mut H) { + self.fields.hash(state); + self.rule.hash(state); + } +} + impl MessageKey { pub(crate) fn new(fields: FieldNames, rule: String) -> Self { Self { fields, rule }