use crate::presentation::{PresentationStartupError, Queryability, Reversibility};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProtectedPresentationScopeMetadata {
pub scope: &'static str,
pub codec_path: &'static str,
pub fallible: bool,
pub reversible: Reversibility,
pub queryability: Queryability,
}
impl ProtectedPresentationScopeMetadata {
#[doc(hidden)]
pub const fn const_new(
scope: &'static str,
codec_path: &'static str,
fallible: bool,
reversible: Reversibility,
queryability: Queryability,
) -> Self {
Self {
scope,
codec_path,
fallible,
reversible,
queryability,
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy)]
pub struct ProtectedPresentationFieldMetadata {
pub model: &'static str,
pub field: &'static str,
pub scopes: &'static [ProtectedPresentationScopeMetadata],
}
impl ProtectedPresentationFieldMetadata {
#[doc(hidden)]
pub const fn const_new(
model: &'static str,
field: &'static str,
scopes: &'static [ProtectedPresentationScopeMetadata],
) -> Self {
Self {
model,
field,
scopes,
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy)]
pub struct PresentationCodecUsage {
pub model: &'static str,
pub field: &'static str,
pub scope: &'static str,
pub codec_path: &'static str,
pub fallible: bool,
pub input_type_name: fn() -> &'static str,
pub output_type_name: fn() -> &'static str,
pub validate_startup: fn() -> Result<(), PresentationStartupError>,
}
impl PresentationCodecUsage {
#[doc(hidden)]
#[allow(clippy::too_many_arguments)]
pub const fn const_new(
model: &'static str,
field: &'static str,
scope: &'static str,
codec_path: &'static str,
fallible: bool,
input_type_name: fn() -> &'static str,
output_type_name: fn() -> &'static str,
validate_startup: fn() -> Result<(), PresentationStartupError>,
) -> Self {
Self {
model,
field,
scope,
codec_path,
fallible,
input_type_name,
output_type_name,
validate_startup,
}
}
}
inventory::collect!(ProtectedPresentationFieldMetadata);
inventory::collect!(PresentationCodecUsage);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scope_metadata_const_new_round_trips_fields() {
let meta = ProtectedPresentationScopeMetadata::const_new(
"public",
"djogi::presentation::builtins::MaskString",
false,
Reversibility::OneWay,
Queryability::Disabled,
);
assert_eq!(meta.scope, "public");
assert_eq!(meta.codec_path, "djogi::presentation::builtins::MaskString");
assert!(!meta.fallible);
assert_eq!(meta.reversible, Reversibility::OneWay);
assert_eq!(meta.queryability, Queryability::Disabled);
}
#[test]
fn field_metadata_const_new_round_trips_fields() {
static SCOPES: &[ProtectedPresentationScopeMetadata] =
&[ProtectedPresentationScopeMetadata {
scope: "admin",
codec_path: "djogi::presentation::builtins::Identity",
fallible: false,
reversible: Reversibility::Reversible,
queryability: Queryability::PredicateAndOrder,
}];
let meta = ProtectedPresentationFieldMetadata::const_new("User", "email", SCOPES);
assert_eq!(meta.model, "User");
assert_eq!(meta.field, "email");
assert_eq!(meta.scopes.len(), 1);
assert_eq!(meta.scopes[0].scope, "admin");
}
#[test]
fn codec_usage_const_new_round_trips_fields() {
fn input_name() -> &'static str {
"String"
}
fn output_name() -> &'static str {
"String"
}
fn validate() -> Result<(), PresentationStartupError> {
Ok(())
}
let usage = PresentationCodecUsage::const_new(
"User",
"email",
"public",
"djogi::presentation::builtins::MaskString",
false,
input_name,
output_name,
validate,
);
assert_eq!(usage.model, "User");
assert_eq!(usage.field, "email");
assert_eq!(usage.scope, "public");
assert_eq!(
usage.codec_path,
"djogi::presentation::builtins::MaskString"
);
assert!(!usage.fallible);
assert_eq!((usage.input_type_name)(), "String");
assert_eq!((usage.output_type_name)(), "String");
assert!((usage.validate_startup)().is_ok());
}
}