#[cfg(feature = "legal")]
use alloc::vec::Vec;
#[cfg(feature = "legal")]
use legalis_core::{Effect, EffectType, Statute};
#[cfg(feature = "legal")]
use super::{LegalContext, sensor::PolicyEngine};
#[cfg(feature = "legal")]
pub struct LegalisPolicyEngine {
statutes: Vec<Statute>,
}
#[cfg(feature = "legal")]
impl LegalisPolicyEngine {
#[must_use]
pub fn new(statutes: Vec<Statute>) -> Self {
Self { statutes }
}
#[must_use]
pub fn gdpr() -> Self {
Self::new(Self::gdpr_statutes())
}
#[must_use]
pub fn ccpa() -> Self {
Self::new(Self::ccpa_statutes())
}
#[must_use]
pub fn lgpd() -> Self {
Self::new(Self::lgpd_statutes())
}
fn gdpr_statutes() -> Vec<Statute> {
alloc::vec![
Statute::new(
"gdpr-art44-transfer",
"GDPR Art. 44 – Personal Data Transfer Restriction",
Effect::prohibition(
"personal data transfer outside EU/EEA without adequacy decision"
),
)
.with_jurisdiction("EU"),
Statute::new(
"gdpr-art5-accountability",
"GDPR Art. 5(2) – Accountability Obligation",
Effect::obligation("audit and demonstrate compliance"),
)
.with_jurisdiction("EU"),
Statute::new(
"gdpr-art15-access",
"GDPR Art. 15 – Right of Access",
Effect::grant("data subject access to personal data"),
)
.with_jurisdiction("EU"),
]
}
fn ccpa_statutes() -> Vec<Statute> {
alloc::vec![
Statute::new(
"ccpa-1798-100",
"CCPA § 1798.100 – Consumer Right to Know",
Effect::grant("consumer right to know about personal information collected"),
)
.with_jurisdiction("US-CA"),
Statute::new(
"ccpa-1798-120",
"CCPA § 1798.120 – Right to Opt-Out",
Effect::grant("consumer right to opt-out of sale of personal information"),
)
.with_jurisdiction("US-CA"),
Statute::new(
"ccpa-audit",
"CCPA – Privacy Notice Obligation",
Effect::obligation("audit privacy practices and provide notice at collection"),
)
.with_jurisdiction("US-CA"),
]
}
fn lgpd_statutes() -> Vec<Statute> {
alloc::vec![
Statute::new(
"lgpd-art46",
"LGPD Art. 46 – Data Security Obligation",
Effect::obligation(
"audit and implement technical and administrative security measures"
),
)
.with_jurisdiction("BR"),
Statute::new(
"lgpd-art33",
"LGPD Art. 33 – International Transfer",
Effect::prohibition("international personal data transfer without legal basis"),
)
.with_jurisdiction("BR"),
]
}
fn apply_effect(ctx: &mut LegalContext, effect: &Effect, statute_jurisdiction: Option<&str>) {
match effect.effect_type {
EffectType::Prohibition => {
if let Some(jur) = statute_jurisdiction {
ctx.blocked_regions.insert(jur.to_string());
}
ctx.data_transfer_allowed = false;
}
EffectType::Grant => {
if effect.description.to_lowercase().contains("transfer") {
ctx.data_transfer_allowed = true;
}
if effect.description.to_lowercase().contains("access") {
ctx.user_consent = true;
}
}
EffectType::Obligation => {
if effect.description.to_lowercase().contains("audit") {
ctx.audit_required = true;
}
if effect.description.to_lowercase().contains("cert") {
let cert_name = effect
.get_parameter("cert_name")
.cloned()
.unwrap_or_else(|| "REQUIRED".to_string());
ctx.required_certifications.insert(cert_name);
}
}
_ => {}
}
}
}
#[cfg(feature = "legal")]
impl PolicyEngine for LegalisPolicyEngine {
fn evaluate_for_jurisdiction(&self, jurisdiction: &str) -> Option<LegalContext> {
let mut ctx = LegalContext::from_legalis_jurisdiction(jurisdiction);
let jur_upper = jurisdiction.to_uppercase();
for statute in &self.statutes {
let matches = statute
.jurisdiction
.as_deref()
.map(|j| j.to_uppercase() == jur_upper)
.unwrap_or(true);
if matches {
Self::apply_effect(&mut ctx, &statute.effect, statute.jurisdiction.as_deref());
}
}
Some(ctx)
}
}