qualia_core_db/query/
cbor_compiler.rs1use crate::NQuin;
2
3#[derive(Debug, PartialEq, Eq)]
4pub enum ParseError {
5 UnsupportedMediaType, MalformedPayload,
7 BufferOverflow,
8}
9
10pub fn ingest_network_payload(payload: &[u8]) -> Result<&[u8], ParseError> {
15 if payload.is_empty() {
16 return Err(ParseError::MalformedPayload);
17 }
18
19 let first_byte = payload[0];
21
22 if first_byte == b'{' || first_byte == b'<' || first_byte == b'@' {
27 return Err(ParseError::UnsupportedMediaType);
28 }
29
30 let is_cbor_map = (0xA0..=0xB7).contains(&first_byte);
33 let is_cbor_array = (0x80..=0x97).contains(&first_byte);
34 let is_cbor_indefinite = first_byte == 0xBF || first_byte == 0x9F;
35
36 if is_cbor_map || is_cbor_array || is_cbor_indefinite {
37 Ok(payload)
38 } else {
39 Err(ParseError::UnsupportedMediaType)
40 }
41}
42
43pub fn parse_cbor_ld_to_quin(payload: &[u8]) -> Result<NQuin, ParseError> {
47 let valid_payload = ingest_network_payload(payload)?;
49
50 let mut cursor = 1; let mut read_cbor_int = || -> Result<u64, ParseError> {
54 if cursor >= valid_payload.len() {
55 return Err(ParseError::BufferOverflow);
56 }
57 let byte = valid_payload[cursor];
58 cursor += 1;
59
60 let major_type = byte >> 5;
61 if major_type != 0 {
63 return Ok(0);
66 }
67
68 let additional_info = byte & 0x1F;
69 match additional_info {
70 0..=23 => Ok(additional_info as u64),
71 24 => {
72 if cursor + 1 > valid_payload.len() {
73 return Err(ParseError::BufferOverflow);
74 }
75 let val = valid_payload[cursor] as u64;
76 cursor += 1;
77 Ok(val)
78 }
79 25 => {
80 if cursor + 2 > valid_payload.len() {
81 return Err(ParseError::BufferOverflow);
82 }
83 let mut bytes = [0u8; 2];
84 bytes.copy_from_slice(&valid_payload[cursor..cursor + 2]);
85 cursor += 2;
86 Ok(u16::from_be_bytes(bytes) as u64)
87 }
88 26 => {
89 if cursor + 4 > valid_payload.len() {
90 return Err(ParseError::BufferOverflow);
91 }
92 let mut bytes = [0u8; 4];
93 bytes.copy_from_slice(&valid_payload[cursor..cursor + 4]);
94 cursor += 4;
95 Ok(u32::from_be_bytes(bytes) as u64)
96 }
97 27 => {
98 if cursor + 8 > valid_payload.len() {
99 return Err(ParseError::BufferOverflow);
100 }
101 let mut bytes = [0u8; 8];
102 bytes.copy_from_slice(&valid_payload[cursor..cursor + 8]);
103 cursor += 8;
104 Ok(u64::from_be_bytes(bytes))
105 }
106 _ => Err(ParseError::MalformedPayload),
107 }
108 };
109
110 let subject = read_cbor_int()?;
113 let predicate = read_cbor_int()?;
114 let object = read_cbor_int()?;
115 let context = read_cbor_int()?;
116
117 let metadata = 0b00 << 61;
119
120 Ok(NQuin {
121 subject,
122 predicate,
123 object,
124 context,
125 metadata,
126 parity: 0, })
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_gatekeeper_rejects_json() {
136 let json_payload = b"{\"@context\": \"http://schema.org\"}";
137 assert_eq!(
138 ingest_network_payload(json_payload),
139 Err(ParseError::UnsupportedMediaType)
140 );
141 }
142
143 #[test]
144 fn test_gatekeeper_rejects_turtle() {
145 let turtle_payload = b"@prefix qualia: <urn:qualia:> .";
146 assert_eq!(
147 ingest_network_payload(turtle_payload),
148 Err(ParseError::UnsupportedMediaType)
149 );
150 }
151
152 #[test]
153 fn test_parse_cbor_ld_dictionary() {
154 let cbor_payload: [u8; 13] = [
161 0x84, 0x19, 0x03, 0xE8, 0x19, 0x07, 0xD0, 0x19, 0x0B, 0xB8, 0x19, 0x0F, 0xA0,
162 ];
163
164 let quin = parse_cbor_ld_to_quin(&cbor_payload).unwrap();
165
166 assert_eq!(quin.subject, 1000);
167 assert_eq!(quin.predicate, 2000);
168 assert_eq!(quin.object, 3000);
169 assert_eq!(quin.context, 4000);
170 }
171
172 #[test]
173 fn test_parse_cbor_buffer_overflow() {
174 let cbor_payload: [u8; 4] = [0x84, 0x19, 0x03, 0xE8];
176 assert_eq!(
177 parse_cbor_ld_to_quin(&cbor_payload),
178 Err(ParseError::BufferOverflow)
179 );
180 }
181}