Skip to main content

qualia_core_db/services/
solid_ldp.rs

1use crate::{
2    NQuin, PermissiveRoutingLane, QualiaSuperBlock, BLOCK_MULTIPLIER_SIZE, QUINS_PER_BLOCK,
3};
4use std::fs::{create_dir_all, File};
5use std::io::{Read, Write};
6use std::path::Path;
7
8pub struct SolidExporter;
9
10impl SolidExporter {
11    /// Translates a raw binary Qualia graph (.q42) into a W3C Solid LDP Basic Container.
12    /// This includes mapping the 48-byte Super-Quins to standard Turtle (.ttl) files
13    /// and generating static Web Access Control (.acl) files for backward compatibility.
14    pub fn export_to_solid_pod(input_q42_path: &str, output_dir_path: &str) -> std::io::Result<()> {
15        let out_dir = Path::new(output_dir_path);
16        create_dir_all(out_dir)?;
17
18        let mut input_file = File::open(input_q42_path)?;
19        let mut turtle_file = File::create(out_dir.join("data.ttl"))?;
20        let mut acl_file = File::create(out_dir.join("data.ttl.acl"))?;
21
22        // Write W3C Solid Turtle Headers
23        writeln!(
24            turtle_file,
25            "@prefix acl: <http://www.w3.org/ns/auth/acl#> ."
26        )?;
27        writeln!(turtle_file, "@prefix foaf: <http://xmlns.com/foaf/0.1/> .")?;
28        writeln!(turtle_file, "@prefix qualia: <urn:qualia:schema:> .")?;
29        writeln!(turtle_file, "")?;
30
31        // Write WAC ACL Headers
32        writeln!(acl_file, "@prefix acl: <http://www.w3.org/ns/auth/acl#> .")?;
33        writeln!(acl_file, "@prefix foaf: <http://xmlns.com/foaf/0.1/> .")?;
34        writeln!(acl_file, "\n# Auto-generated by Qualia-DB Solid Exporter")?;
35
36        let mut block = Box::new(unsafe { std::mem::zeroed::<QualiaSuperBlock>() });
37        let block_slice = unsafe {
38            std::slice::from_raw_parts_mut(
39                &mut *block as *mut QualiaSuperBlock as *mut u8,
40                BLOCK_MULTIPLIER_SIZE,
41            )
42        };
43
44        // Stream the binary graph zero-allocation style
45        let mut quin_count = 0;
46        let mut has_permissive_commons = false;
47
48        loop {
49            let bytes_read = input_file.read(block_slice)?;
50            if bytes_read == 0 {
51                break;
52            }
53            if bytes_read < BLOCK_MULTIPLIER_SIZE {
54                // Incomplete block, ignore for now
55                break;
56            }
57
58            let active_quins = block.active_quin_count as usize;
59            for i in 0..active_quins.min(QUINS_PER_BLOCK) {
60                let quin = &block.quin_ledger[i];
61                if !quin.verify_ecc_parity() {
62                    continue;
63                }
64
65                // Write Turtle Data
66                writeln!(turtle_file, "{}", Self::quin_to_turtle(quin))?;
67
68                // Check N3Logic Routing Lane for ACL translation
69                if quin.identify_routing_lane() == PermissiveRoutingLane::EnforcePermissiveCommons {
70                    has_permissive_commons = true;
71                }
72                quin_count += 1;
73            }
74        }
75
76        // Generate WAC rules based on N3Logic heuristics
77        if has_permissive_commons {
78            writeln!(acl_file, "\n<#publicAccess> a acl:Authorization ;")?;
79            writeln!(acl_file, "    acl:agentClass foaf:Agent ;")?; // Public
80            writeln!(acl_file, "    acl:accessTo <./data.ttl> ;")?;
81            writeln!(acl_file, "    acl:mode acl:Read .")?;
82        }
83
84        // Default Private Owner Rule (Everything else requires strict control)
85        writeln!(acl_file, "\n<#ownerAccess> a acl:Authorization ;")?;
86        writeln!(acl_file, "    acl:agent <urn:qualia:owner> ;")?;
87        writeln!(acl_file, "    acl:accessTo <./data.ttl> ;")?;
88        writeln!(acl_file, "    acl:mode acl:Read, acl:Write, acl:Control .")?;
89
90        // Zero-scrub the transient buffer to enforce memory integrity
91        unsafe {
92            for byte in block_slice.iter_mut() {
93                core::ptr::write_volatile(byte, 0);
94            }
95        }
96
97        println!(
98            "Successfully exported {} Quins to W3C Solid Container at: {}",
99            quin_count, output_dir_path
100        );
101        Ok(())
102    }
103
104    /// Helper to translate a 48-byte Super-Quin into a W3C Turtle string.
105    fn quin_to_turtle(quin: &NQuin) -> String {
106        // We use pseudo-URIs here. A real lexicon lookup would happen for string resolution.
107        // N3Logic Context (Vector 4) is appended as a comment since Turtle does not support quads.
108        format!(
109            "<urn:qualia:node:{}> <urn:qualia:pred:{}> <urn:qualia:node:{}> . # Context: {}",
110            quin.subject, quin.predicate, quin.object, quin.context
111        )
112    }
113}
114
115// Backward compatibility stub for old tests
116pub struct SolidLdpFacade;
117impl SolidLdpFacade {
118    pub fn serialize_to_rdf_star(quin: &NQuin) -> String {
119        format!("GRAPH <urn:qualia:context:{}> {{ geo:asWKT qualia:hardwareIntegrity \"VERIFIED_ECC_PASS\" }}", quin.context)
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn test_allocation_firewall() {
129        // Assert that the `QualiaSuperBlock` buffer contains precisely what we expect
130        // without heap allocation.
131        assert_eq!(
132            std::mem::size_of::<QualiaSuperBlock>(),
133            crate::BLOCK_MULTIPLIER_SIZE
134        );
135        let mut block = Box::new(unsafe { std::mem::zeroed::<QualiaSuperBlock>() });
136        let block_slice = unsafe {
137            std::slice::from_raw_parts_mut(
138                &mut *block as *mut QualiaSuperBlock as *mut u8,
139                crate::BLOCK_MULTIPLIER_SIZE,
140            )
141        };
142
143        // Zero-scrub
144        unsafe {
145            for byte in block_slice.iter_mut() {
146                core::ptr::write_volatile(byte, 0);
147            }
148        }
149
150        // Check that the memory was effectively zeroed
151        for &byte in block_slice.iter() {
152            assert_eq!(byte, 0);
153        }
154    }
155}