use std::collections::BTreeMap;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AasaDocument {
pub applinks: Option<AppLinks>,
pub webcredentials: Option<AppService>,
pub appclips: Option<AppService>,
pub activitycontinuation: Option<AppService>,
pub unknown_keys: Vec<String>,
pub(crate) structural: Vec<crate::diagnostics::Diagnostic>,
pub(crate) byte_len: usize,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct AppService {
pub apps: Vec<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct AppLinks {
pub apps: Option<Vec<String>>,
pub defaults: Option<MatchDefaults>,
pub details: Vec<AppLinkDetail>,
pub substitution_variables: BTreeMap<String, Vec<String>>,
pub details_were_dictionary: bool,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct AppLinkDetail {
pub app_id: Option<String>,
pub app_ids: Option<Vec<String>>,
pub components: Option<Vec<ComponentRule>>,
pub paths: Option<Vec<String>>,
pub defaults: Option<MatchDefaults>,
}
impl AppLinkDetail {
#[must_use]
pub fn declared_app_ids(&self) -> Vec<&str> {
let mut out = Vec::new();
if let Some(app_id) = &self.app_id {
out.push(app_id.as_str());
}
if let Some(app_ids) = &self.app_ids {
out.extend(app_ids.iter().map(String::as_str));
}
out
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ComponentRule {
pub path: Option<String>,
pub query: Option<QueryRule>,
pub fragment: Option<String>,
pub exclude: Option<bool>,
pub comment: Option<String>,
pub case_sensitive: Option<bool>,
pub percent_encoded: Option<bool>,
}
impl ComponentRule {
#[must_use]
pub fn is_unconstrained(&self) -> bool {
self.path.is_none() && self.query.is_none() && self.fragment.is_none()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QueryRule {
Whole(String),
Items(BTreeMap<String, QueryPredicate>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QueryPredicate {
Pattern(String),
Unsupported {
json_type: &'static str,
},
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct MatchDefaults {
pub case_sensitive: Option<bool>,
pub percent_encoded: Option<bool>,
pub other_keys: Vec<String>,
}
impl MatchDefaults {
#[must_use]
pub fn is_empty(&self) -> bool {
self.case_sensitive.is_none() && self.percent_encoded.is_none()
}
}
pub const DEFAULT_CASE_SENSITIVE: bool = true;
pub const DEFAULT_PERCENT_ENCODED: bool = true;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
pub struct EffectiveDefaults {
pub case_sensitive: bool,
pub percent_encoded: bool,
}
impl Default for EffectiveDefaults {
fn default() -> Self {
Self {
case_sensitive: DEFAULT_CASE_SENSITIVE,
percent_encoded: DEFAULT_PERCENT_ENCODED,
}
}
}
impl EffectiveDefaults {
#[must_use]
pub fn overridden_by(self, defaults: Option<&MatchDefaults>) -> Self {
let Some(defaults) = defaults else {
return self;
};
Self {
case_sensitive: defaults.case_sensitive.unwrap_or(self.case_sensitive),
percent_encoded: defaults.percent_encoded.unwrap_or(self.percent_encoded),
}
}
}