use { crate::{ config::{ ClientMatch, GenericMatch, MatchExactly, context::Context, extractor::{Extractor, ExtractorError, arr, bol, n32, opt, s32, str, val}, parser::{DataType, ParseResult, Parser, UnexpectedDataType}, }, toml::{ toml_span::{DespanExt, Span, Spanned}, toml_value::Value, }, }, indexmap::IndexMap, thiserror::Error, }; #[derive(Debug, Error)] pub enum ClientMatchParserError { #[error(transparent)] Expected(#[from] UnexpectedDataType), #[error(transparent)] Extract(#[from] ExtractorError), } pub struct ClientMatchParser<'a>(pub &'a Context<'a>); impl Parser for ClientMatchParser<'_> { type Value = ClientMatch; type Error = ClientMatchParserError; const EXPECTED: &'static [DataType] = &[DataType::Table]; fn parse_table( &mut self, span: Span, table: &IndexMap, Spanned>, ) -> ParseResult { let mut ext = Extractor::new(self.0, span, table); let ( ( name, not_val, all_val, any_val, exactly_val, sandboxed, sandbox_engine, sandbox_engine_regex, sandbox_app_id, sandbox_app_id_regex, ), ( sandbox_instance_id, sandbox_instance_id_regex, uid, pid, is_xwayland, comm, comm_regex, exe, exe_regex, ), ) = ext.extract(( ( opt(str("name")), opt(val("not")), opt(arr("all")), opt(arr("any")), opt(val("exactly")), opt(bol("sandboxed")), opt(str("sandbox-engine")), opt(str("sandbox-engine-regex")), opt(str("sandbox-app-id")), opt(str("sandbox-app-id-regex")), ), ( opt(str("sandbox-instance-id")), opt(str("sandbox-instance-id-regex")), opt(s32("uid")), opt(s32("pid")), opt(bol("is-xwayland")), opt(str("comm")), opt(str("comm-regex")), opt(str("exe")), opt(str("exe-regex")), ), ))?; let mut not = None; if let Some(value) = not_val { not = Some(Box::new(value.parse(&mut ClientMatchParser(self.0))?)); } macro_rules! list { ($val:expr) => {{ let mut list = None; if let Some(value) = $val { let mut res = vec![]; for value in value.value { res.push(value.parse(&mut ClientMatchParser(self.0))?); } list = Some(res); } list }}; } let all = list!(all_val); let any = list!(any_val); let mut exactly = None; if let Some(value) = exactly_val { exactly = Some(value.parse(&mut ClientMatchExactlyParser(self.0))?); } Ok(ClientMatch { generic: GenericMatch { name: name.despan_into(), not, all, any, exactly, }, sandbox_engine: sandbox_engine.despan_into(), sandbox_engine_regex: sandbox_engine_regex.despan_into(), sandbox_app_id: sandbox_app_id.despan_into(), sandbox_app_id_regex: sandbox_app_id_regex.despan_into(), sandbox_instance_id: sandbox_instance_id.despan_into(), sandbox_instance_id_regex: sandbox_instance_id_regex.despan_into(), sandboxed: sandboxed.despan(), uid: uid.despan(), pid: pid.despan(), is_xwayland: is_xwayland.despan(), comm: comm.despan_into(), comm_regex: comm_regex.despan_into(), exe: exe.despan_into(), exe_regex: exe_regex.despan_into(), }) } } pub struct ClientMatchExactlyParser<'a>(pub &'a Context<'a>); impl Parser for ClientMatchExactlyParser<'_> { type Value = MatchExactly; type Error = ClientMatchParserError; const EXPECTED: &'static [DataType] = &[DataType::Table]; fn parse_table( &mut self, span: Span, table: &IndexMap, Spanned>, ) -> ParseResult { let mut ext = Extractor::new(self.0, span, table); let (num, list_val) = ext.extract((n32("num"), arr("list")))?; let mut list = vec![]; for el in list_val.value { list.push(el.parse(&mut ClientMatchParser(self.0))?); } Ok(MatchExactly { num: num.value as _, list, }) } }