solid_pod_rs/wac/
serializer.rs1use crate::wac::conditions::Condition;
4use crate::wac::document::{AclDocument, IdOrIds};
5
6pub fn serialize_turtle_acl(doc: &AclDocument) -> String {
8 let mut out = String::new();
9 out.push_str("@prefix acl: <http://www.w3.org/ns/auth/acl#> .\n");
10 out.push_str("@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n");
11 let graph = match &doc.graph {
12 Some(g) => g,
13 None => return out,
14 };
15 for (i, auth) in graph.iter().enumerate() {
16 let subject = format!("<#rule-{i}>");
17 out.push_str(&subject);
18 out.push_str(" a acl:Authorization");
19 emit_pairs(&mut out, "acl:agent", &auth.agent);
20 emit_pairs(&mut out, "acl:agentClass", &auth.agent_class);
21 emit_pairs(&mut out, "acl:agentGroup", &auth.agent_group);
22 emit_pairs(&mut out, "acl:origin", &auth.origin);
23 emit_pairs(&mut out, "acl:accessTo", &auth.access_to);
24 emit_pairs(&mut out, "acl:default", &auth.default);
25 emit_pairs(&mut out, "acl:mode", &auth.mode);
26 emit_conditions(&mut out, auth.condition.as_deref());
27 out.push_str(" .\n\n");
28 }
29 out
30}
31
32fn emit_pairs(out: &mut String, pred: &str, vals: &Option<IdOrIds>) {
33 if let Some(ids) = vals {
34 let refs: Vec<&str> = match ids {
35 IdOrIds::Single(r) => vec![r.id.as_str()],
36 IdOrIds::Multiple(v) => v.iter().map(|r| r.id.as_str()).collect(),
37 };
38 if refs.is_empty() {
39 return;
40 }
41 out.push_str(" ;\n ");
42 out.push_str(pred);
43 out.push(' ');
44 let rendered: Vec<String> = refs
45 .iter()
46 .map(|r| {
47 if r.starts_with("http") {
48 format!("<{r}>")
49 } else {
50 r.to_string()
51 }
52 })
53 .collect();
54 out.push_str(&rendered.join(", "));
55 }
56}
57
58fn emit_conditions(out: &mut String, conds: Option<&[Condition]>) {
59 let conds = match conds {
60 Some(c) if !c.is_empty() => c,
61 _ => return,
62 };
63 for cond in conds {
64 out.push_str(" ;\n acl:condition [\n a ");
65 out.push_str(cond.type_iri());
66 match cond {
67 Condition::Client(body) => {
68 emit_body_pair(out, "acl:client", &body.client);
69 emit_body_pair(out, "acl:clientGroup", &body.client_group);
70 emit_body_pair(out, "acl:clientClass", &body.client_class);
71 }
72 Condition::Issuer(body) => {
73 emit_body_pair(out, "acl:issuer", &body.issuer);
74 emit_body_pair(out, "acl:issuerGroup", &body.issuer_group);
75 emit_body_pair(out, "acl:issuerClass", &body.issuer_class);
76 }
77 Condition::Unknown { .. } => {}
78 }
79 out.push_str("\n ]");
80 }
81}
82
83fn emit_body_pair(out: &mut String, pred: &str, vals: &Option<IdOrIds>) {
84 if let Some(ids) = vals {
85 let refs: Vec<&str> = match ids {
86 IdOrIds::Single(r) => vec![r.id.as_str()],
87 IdOrIds::Multiple(v) => v.iter().map(|r| r.id.as_str()).collect(),
88 };
89 if refs.is_empty() {
90 return;
91 }
92 out.push_str(" ;\n ");
93 out.push_str(pred);
94 out.push(' ');
95 let rendered: Vec<String> = refs
96 .iter()
97 .map(|r| {
98 if r.starts_with("http") {
99 format!("<{r}>")
100 } else {
101 r.to_string()
102 }
103 })
104 .collect();
105 out.push_str(&rendered.join(", "));
106 }
107}