+109
crates/jacquard-common/src/types/value.rs
+109
crates/jacquard-common/src/types/value.rs
···
117
117
Data::from_json(&json).map(|data| data.into_static())
118
118
}
119
119
120
+
/// Get as object if this is an Object variant
121
+
pub fn as_object(&self) -> Option<&Object<'s>> {
122
+
if let Data::Object(obj) = self {
123
+
Some(obj)
124
+
} else {
125
+
None
126
+
}
127
+
}
128
+
129
+
/// Get as array if this is an Array variant
130
+
pub fn as_array(&self) -> Option<&Array<'s>> {
131
+
if let Data::Array(arr) = self {
132
+
Some(arr)
133
+
} else {
134
+
None
135
+
}
136
+
}
137
+
138
+
/// Get as string if this is a String variant
139
+
pub fn as_str(&self) -> Option<&str> {
140
+
if let Data::String(s) = self {
141
+
Some(s.as_str())
142
+
} else {
143
+
None
144
+
}
145
+
}
146
+
147
+
/// Get as integer if this is an Integer variant
148
+
pub fn as_integer(&self) -> Option<i64> {
149
+
if let Data::Integer(i) = self {
150
+
Some(*i)
151
+
} else {
152
+
None
153
+
}
154
+
}
155
+
156
+
/// Get as boolean if this is a Boolean variant
157
+
pub fn as_boolean(&self) -> Option<bool> {
158
+
if let Data::Boolean(b) = self {
159
+
Some(*b)
160
+
} else {
161
+
None
162
+
}
163
+
}
164
+
165
+
/// Check if this is a null value
166
+
pub fn is_null(&self) -> bool {
167
+
matches!(self, Data::Null)
168
+
}
169
+
170
+
/// Serialize to canonical DAG-CBOR bytes for CID computation
171
+
///
172
+
/// This produces the deterministic CBOR encoding used for content-addressing.
173
+
pub fn to_dag_cbor(
174
+
&self,
175
+
) -> Result<Vec<u8>, serde_ipld_dagcbor::EncodeError<std::collections::TryReserveError>> {
176
+
serde_ipld_dagcbor::to_vec(self)
177
+
}
178
+
120
179
/// Parse a Data value from an IPLD value (CBOR)
121
180
pub fn from_cbor(cbor: &'s Ipld) -> Result<Self, AtDataError> {
122
181
Ok(match cbor {
···
358
417
}
359
418
360
419
impl<'d> RawData<'d> {
420
+
/// Get as object if this is an Object variant
421
+
pub fn as_object(&self) -> Option<&BTreeMap<SmolStr, RawData<'d>>> {
422
+
if let RawData::Object(obj) = self {
423
+
Some(obj)
424
+
} else {
425
+
None
426
+
}
427
+
}
428
+
429
+
/// Get as array if this is an Array variant
430
+
pub fn as_array(&self) -> Option<&Vec<RawData<'d>>> {
431
+
if let RawData::Array(arr) = self {
432
+
Some(arr)
433
+
} else {
434
+
None
435
+
}
436
+
}
437
+
438
+
/// Get as string if this is a String variant
439
+
pub fn as_str(&self) -> Option<&str> {
440
+
if let RawData::String(s) = self {
441
+
Some(s.as_ref())
442
+
} else {
443
+
None
444
+
}
445
+
}
446
+
447
+
/// Get as boolean if this is a Boolean variant
448
+
pub fn as_boolean(&self) -> Option<bool> {
449
+
if let RawData::Boolean(b) = self {
450
+
Some(*b)
451
+
} else {
452
+
None
453
+
}
454
+
}
455
+
456
+
/// Check if this is a null value
457
+
pub fn is_null(&self) -> bool {
458
+
matches!(self, RawData::Null)
459
+
}
460
+
461
+
/// Serialize to canonical DAG-CBOR bytes for CID computation
462
+
///
463
+
/// This produces the deterministic CBOR encoding used for content-addressing.
464
+
pub fn to_dag_cbor(
465
+
&self,
466
+
) -> Result<Vec<u8>, serde_ipld_dagcbor::EncodeError<std::collections::TryReserveError>> {
467
+
serde_ipld_dagcbor::to_vec(self)
468
+
}
469
+
361
470
/// Convert a CBOR-encoded byte slice into a `RawData` value.
362
471
/// Parse a Data value from an IPLD value (CBOR)
363
472
pub fn from_cbor(cbor: &'d Ipld) -> Result<Self, AtDataError> {
+117
crates/jacquard-common/src/types/value/tests.rs
+117
crates/jacquard-common/src/types/value/tests.rs
···
813
813
assert_eq!(result.text, "null test");
814
814
assert_eq!(result.langs, None);
815
815
}
816
+
817
+
#[test]
818
+
fn test_data_accessors() {
819
+
// Test as_object
820
+
let mut map = BTreeMap::new();
821
+
map.insert(SmolStr::new_static("key"), Data::Integer(42));
822
+
let obj_data = Data::Object(Object(map.clone()));
823
+
assert!(obj_data.as_object().is_some());
824
+
assert_eq!(obj_data.as_object().unwrap().0.len(), 1);
825
+
assert!(Data::Null.as_object().is_none());
826
+
827
+
// Test as_array
828
+
let arr_data = Data::Array(Array(vec![Data::Integer(1), Data::Integer(2)]));
829
+
assert!(arr_data.as_array().is_some());
830
+
assert_eq!(arr_data.as_array().unwrap().0.len(), 2);
831
+
assert!(Data::Null.as_array().is_none());
832
+
833
+
// Test as_str
834
+
let str_data = Data::String(AtprotoStr::String("hello".into()));
835
+
assert_eq!(str_data.as_str(), Some("hello"));
836
+
assert!(Data::Null.as_str().is_none());
837
+
838
+
// Test as_integer
839
+
let int_data = Data::Integer(42);
840
+
assert_eq!(int_data.as_integer(), Some(42));
841
+
assert!(Data::Null.as_integer().is_none());
842
+
843
+
// Test as_boolean
844
+
let bool_data = Data::Boolean(true);
845
+
assert_eq!(bool_data.as_boolean(), Some(true));
846
+
assert!(Data::Null.as_boolean().is_none());
847
+
848
+
// Test is_null
849
+
assert!(Data::Null.is_null());
850
+
assert!(!Data::Integer(0).is_null());
851
+
}
852
+
853
+
#[test]
854
+
fn test_rawdata_accessors() {
855
+
// Test as_object
856
+
let mut map = BTreeMap::new();
857
+
map.insert(SmolStr::new_static("key"), RawData::SignedInt(42));
858
+
let obj_data = RawData::Object(map.clone());
859
+
assert!(obj_data.as_object().is_some());
860
+
assert_eq!(obj_data.as_object().unwrap().len(), 1);
861
+
assert!(RawData::Null.as_object().is_none());
862
+
863
+
// Test as_array
864
+
let arr_data = RawData::Array(vec![RawData::SignedInt(1), RawData::SignedInt(2)]);
865
+
assert!(arr_data.as_array().is_some());
866
+
assert_eq!(arr_data.as_array().unwrap().len(), 2);
867
+
assert!(RawData::Null.as_array().is_none());
868
+
869
+
// Test as_str
870
+
let str_data = RawData::String("hello".into());
871
+
assert_eq!(str_data.as_str(), Some("hello"));
872
+
assert!(RawData::Null.as_str().is_none());
873
+
874
+
// Test as_boolean
875
+
let bool_data = RawData::Boolean(true);
876
+
assert_eq!(bool_data.as_boolean(), Some(true));
877
+
assert!(RawData::Null.as_boolean().is_none());
878
+
879
+
// Test is_null
880
+
assert!(RawData::Null.is_null());
881
+
assert!(!RawData::SignedInt(0).is_null());
882
+
}
883
+
884
+
#[test]
885
+
fn test_data_to_dag_cbor() {
886
+
// Test simple types
887
+
let null_data = Data::Null;
888
+
assert!(null_data.to_dag_cbor().is_ok());
889
+
890
+
let int_data = Data::Integer(42);
891
+
assert!(int_data.to_dag_cbor().is_ok());
892
+
893
+
let str_data = Data::String(AtprotoStr::String("hello".into()));
894
+
assert!(str_data.to_dag_cbor().is_ok());
895
+
896
+
// Test complex types
897
+
let mut map = BTreeMap::new();
898
+
map.insert(SmolStr::new_static("num"), Data::Integer(42));
899
+
map.insert(SmolStr::new_static("text"), Data::String(AtprotoStr::String("test".into())));
900
+
let obj_data = Data::Object(Object(map));
901
+
let cbor_result = obj_data.to_dag_cbor();
902
+
assert!(cbor_result.is_ok());
903
+
assert!(!cbor_result.unwrap().is_empty());
904
+
905
+
// Test array
906
+
let arr_data = Data::Array(Array(vec![Data::Integer(1), Data::Integer(2), Data::Integer(3)]));
907
+
let arr_cbor = arr_data.to_dag_cbor();
908
+
assert!(arr_cbor.is_ok());
909
+
assert!(!arr_cbor.unwrap().is_empty());
910
+
}
911
+
912
+
#[test]
913
+
fn test_rawdata_to_dag_cbor() {
914
+
// Test simple types
915
+
let null_data = RawData::Null;
916
+
assert!(null_data.to_dag_cbor().is_ok());
917
+
918
+
let int_data = RawData::SignedInt(42);
919
+
assert!(int_data.to_dag_cbor().is_ok());
920
+
921
+
let str_data = RawData::String("hello".into());
922
+
assert!(str_data.to_dag_cbor().is_ok());
923
+
924
+
// Test complex types
925
+
let mut map = BTreeMap::new();
926
+
map.insert(SmolStr::new_static("num"), RawData::SignedInt(42));
927
+
map.insert(SmolStr::new_static("text"), RawData::String("test".into()));
928
+
let obj_data = RawData::Object(map);
929
+
let cbor_result = obj_data.to_dag_cbor();
930
+
assert!(cbor_result.is_ok());
931
+
assert!(!cbor_result.unwrap().is_empty());
932
+
}
+1
-1
crates/jacquard-derive/src/lib.rs
+1
-1
crates/jacquard-derive/src/lib.rs
···
167
167
/// **What it generates:**
168
168
/// - `impl LexiconSchema` with `nsid()`, `schema_id()`, and `lexicon_doc()` methods
169
169
/// - `validate()` method that checks constraints at runtime
170
-
/// - `inventory::submit!` registration for schema discovery (Phase 3)
170
+
/// - `inventory::submit!` registration for schema discovery
171
171
///
172
172
/// **Attributes:** `#[lexicon(...)]` and `#[nsid = "..."]` on types and fields.
173
173
/// See crate docs for full attribute reference and examples.
+1
-9
crates/jacquard-derive/tests/lexicon_schema_derive.rs
+1
-9
crates/jacquard-derive/tests/lexicon_schema_derive.rs
···
1
1
use jacquard_common::CowStr;
2
2
use jacquard_common::types::string::Datetime;
3
3
use jacquard_derive::{LexiconSchema, open_union};
4
-
use jacquard_lexicon::schema::{LexiconGenerator, LexiconSchema as LexiconSchemaTrait};
4
+
use jacquard_lexicon::schema::LexiconSchema as LexiconSchemaTrait;
5
5
use serde::{Deserialize, Serialize};
6
6
7
7
#[test]
···
18
18
assert_eq!(SimpleRecord::nsid(), "com.example.simple");
19
19
assert_eq!(SimpleRecord::schema_id().as_ref(), "com.example.simple");
20
20
21
-
let mut generator = LexiconGenerator::new(SimpleRecord::nsid());
22
21
let doc = SimpleRecord::lexicon_doc();
23
22
24
23
assert_eq!(doc.id.as_ref(), "com.example.simple");
···
46
45
pub score: i64,
47
46
}
48
47
49
-
let mut generator = LexiconGenerator::new(ConstrainedRecord::nsid());
50
48
let doc = ConstrainedRecord::lexicon_doc();
51
49
52
50
let json = serde_json::to_string_pretty(&doc).unwrap();
···
109
107
pub some_field: i64,
110
108
pub another_field: i64,
111
109
}
112
-
113
-
let mut generator = LexiconGenerator::new(RenamedRecord::nsid());
114
110
let doc = RenamedRecord::lexicon_doc();
115
111
116
112
let json = serde_json::to_string_pretty(&doc).unwrap();
···
184
180
Unknown(jacquard_common::types::value::Data<'a>),
185
181
}
186
182
187
-
let mut generator = LexiconGenerator::new(OpenUnion::nsid());
188
183
let doc = OpenUnion::lexicon_doc();
189
184
190
185
let json = serde_json::to_string_pretty(&doc).unwrap();
···
206
201
Video,
207
202
}
208
203
209
-
let mut generator = LexiconGenerator::new(RenamedUnion::nsid());
210
204
let doc = RenamedUnion::lexicon_doc();
211
205
212
206
let json = serde_json::to_string_pretty(&doc).unwrap();
···
229
223
#[allow(dead_code)]
230
224
VariantTwo,
231
225
}
232
-
233
-
let mut generator = LexiconGenerator::new(FragmentUnion::nsid());
234
226
let doc = FragmentUnion::lexicon_doc();
235
227
236
228
let json = serde_json::to_string_pretty(&doc).unwrap();
+1
-1
crates/jacquard-lexicon/src/codegen/schema_impl.rs
+1
-1
crates/jacquard-lexicon/src/codegen/schema_impl.rs
···
2
2
3
3
use crate::derive_impl::doc_to_tokens;
4
4
use crate::lexicon::{
5
-
LexArrayItem, LexInteger, LexObject, LexObjectProperty, LexRecord, LexRecordRecord, LexString,
5
+
LexInteger, LexObject, LexObjectProperty, LexRecordRecord, LexString,
6
6
LexUserType, LexiconDoc,
7
7
};
8
8
use crate::schema::from_ast::{ConstraintCheck, ValidationCheck};
+1
-3
crates/jacquard-lexicon/src/codegen/structs.rs
+1
-3
crates/jacquard-lexicon/src/codegen/structs.rs
···
1
1
use crate::error::Result;
2
2
use crate::lexicon::{
3
-
LexArrayItem, LexInteger, LexObject, LexObjectProperty, LexRecord, LexString, LexUserType,
4
-
Lexicon, LexiconDoc,
3
+
LexArrayItem, LexInteger, LexObject, LexObjectProperty, LexRecord, LexString,
5
4
};
6
5
use heck::{ToPascalCase, ToSnakeCase};
7
6
use proc_macro2::TokenStream;
8
7
use quote::quote;
9
-
use std::collections::BTreeMap;
10
8
11
9
use super::CodeGenerator;
12
10
use super::utils::{make_ident, value_to_variant_name};
+2
-6
crates/jacquard-lexicon/src/derive_impl/lexicon_schema.rs
+2
-6
crates/jacquard-lexicon/src/derive_impl/lexicon_schema.rs
···
69
69
}
70
70
71
71
fn lexicon_doc(
72
-
_generator: &mut ::jacquard_lexicon::schema::LexiconGenerator
73
72
) -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
74
73
#doc_tokens
75
74
}
···
84
83
::jacquard_lexicon::schema::LexiconSchemaRef {
85
84
nsid: #nsid,
86
85
provider: || {
87
-
let mut generator = ::jacquard_lexicon::schema::LexiconGenerator::new(#nsid);
88
-
<#name as ::jacquard_lexicon::schema::LexiconSchema>::lexicon_doc(&mut generator)
86
+
<#name as ::jacquard_lexicon::schema::LexiconSchema>::lexicon_doc()
89
87
},
90
88
}
91
89
}
···
124
122
}
125
123
126
124
fn lexicon_doc(
127
-
_generator: &mut ::jacquard_lexicon::schema::LexiconGenerator
128
125
) -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
129
126
#doc_tokens
130
127
}
···
138
135
::jacquard_lexicon::schema::LexiconSchemaRef {
139
136
nsid: #nsid,
140
137
provider: || {
141
-
let mut generator = ::jacquard_lexicon::schema::LexiconGenerator::new(#nsid);
142
-
<#name as ::jacquard_lexicon::schema::LexiconSchema>::lexicon_doc(&mut generator)
138
+
<#name as ::jacquard_lexicon::schema::LexiconSchema>::lexicon_doc()
143
139
},
144
140
}
145
141
}
+1
-1
crates/jacquard-lexicon/src/schema.rs
+1
-1
crates/jacquard-lexicon/src/schema.rs