use crate::spec::MaskSpec;
use crate::trie::MaskTrie;
use crate::validate::validate_one;
use crate::FieldMaskError;
use std::collections::BTreeSet;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FieldMask {
all: bool,
raw: String,
pub(crate) paths: BTreeSet<Vec<String>>,
}
impl FieldMask {
pub fn parse(raw: &str) -> Result<Self, FieldMaskError> {
let s = raw.trim();
if s.is_empty() {
return Ok(Self {
all: false,
raw: raw.to_string(),
paths: BTreeSet::new(),
});
}
if s == "*" {
return Ok(Self {
all: true,
raw: s.to_string(),
paths: BTreeSet::new(),
});
}
let mut set = BTreeSet::new();
for token in s.split(',') {
let token = token.trim();
if token.is_empty() {
continue;
}
let segs: Vec<String> = token
.split('.')
.map(|t| t.trim())
.filter(|t| !t.is_empty())
.map(|t| t.to_string())
.collect();
if segs.is_empty() {
return Err(FieldMaskError::InvalidSyntax);
}
set.insert(segs);
}
Ok(Self {
all: false,
raw: raw.to_string(),
paths: set,
})
}
pub fn all() -> Self {
Self {
all: true,
raw: "*".into(),
paths: BTreeSet::new(),
}
}
pub fn is_all(&self) -> bool {
self.all
}
pub fn is_empty(&self) -> bool {
!self.all && self.paths.is_empty()
}
pub fn raw(&self) -> &str {
&self.raw
}
pub fn contains_exact<T: MaskSpec>(&self, path: &str) -> Result<bool, FieldMaskError> {
if self.is_all() {
return Ok(true);
}
let segs = parse_path(path)?;
validate_one(&segs, T::mask_spec(), path.to_string())?;
let trie = MaskTrie::new(self);
Ok(trie.contains_path(&segs))
}
pub fn intersects<T: MaskSpec>(&self, path: &str) -> Result<bool, FieldMaskError> {
if self.is_all() {
return Ok(true);
}
let segs = parse_path(path)?;
validate_one(&segs, T::mask_spec(), path.to_string())?;
let trie = MaskTrie::new(self);
if trie.contains_path(&segs) {
return Ok(true);
}
for p in &self.paths {
if p.starts_with(&segs) {
return Ok(true);
}
}
Ok(false)
}
}
fn parse_path(path: &str) -> Result<Vec<String>, FieldMaskError> {
let v: Vec<String> = path
.split('.')
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
if v.is_empty() {
Err(FieldMaskError::InvalidSyntax)
} else {
Ok(v)
}
}