jacquard_api/sh_weaver/edit/
root.rs1#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::CowStr;
14
15#[allow(unused_imports)]
16use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
17use jacquard_common::types::blob::BlobRef;
18use jacquard_common::types::collection::{Collection, RecordError};
19use jacquard_common::types::string::{AtUri, Cid};
20use jacquard_common::types::uri::{RecordUri, UriError};
21use jacquard_common::xrpc::XrpcResp;
22use jacquard_derive::{IntoStatic, lexicon};
23use jacquard_lexicon::lexicon::LexiconDoc;
24use jacquard_lexicon::schema::LexiconSchema;
25
26#[allow(unused_imports)]
27use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
28use serde::{Serialize, Deserialize};
29use crate::sh_weaver::edit::DocRef;
30#[lexicon]
33#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
34#[serde(rename_all = "camelCase", rename = "sh.weaver.edit.root", tag = "$type")]
35pub struct Root<'a> {
36 #[serde(borrow)]
37 pub doc: DocRef<'a>,
38 #[serde(borrow)]
39 pub snapshot: BlobRef<'a>,
40}
41
42#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
45#[serde(rename_all = "camelCase")]
46pub struct RootGetRecordOutput<'a> {
47 #[serde(skip_serializing_if = "Option::is_none")]
48 #[serde(borrow)]
49 pub cid: Option<Cid<'a>>,
50 #[serde(borrow)]
51 pub uri: AtUri<'a>,
52 #[serde(borrow)]
53 pub value: Root<'a>,
54}
55
56impl<'a> Root<'a> {
57 pub fn uri(
58 uri: impl Into<CowStr<'a>>,
59 ) -> Result<RecordUri<'a, RootRecord>, UriError> {
60 RecordUri::try_from_uri(AtUri::new_cow(uri.into())?)
61 }
62}
63
64#[derive(Debug, Serialize, Deserialize)]
67pub struct RootRecord;
68impl XrpcResp for RootRecord {
69 const NSID: &'static str = "sh.weaver.edit.root";
70 const ENCODING: &'static str = "application/json";
71 type Output<'de> = RootGetRecordOutput<'de>;
72 type Err<'de> = RecordError<'de>;
73}
74
75impl From<RootGetRecordOutput<'_>> for Root<'_> {
76 fn from(output: RootGetRecordOutput<'_>) -> Self {
77 use jacquard_common::IntoStatic;
78 output.value.into_static()
79 }
80}
81
82impl Collection for Root<'_> {
83 const NSID: &'static str = "sh.weaver.edit.root";
84 type Record = RootRecord;
85}
86
87impl Collection for RootRecord {
88 const NSID: &'static str = "sh.weaver.edit.root";
89 type Record = RootRecord;
90}
91
92impl<'a> LexiconSchema for Root<'a> {
93 fn nsid() -> &'static str {
94 "sh.weaver.edit.root"
95 }
96 fn def_name() -> &'static str {
97 "main"
98 }
99 fn lexicon_doc() -> LexiconDoc<'static> {
100 lexicon_doc_sh_weaver_edit_root()
101 }
102 fn validate(&self) -> Result<(), ConstraintError> {
103 {
104 let value = &self.snapshot;
105 {
106 let size = value.blob().size;
107 if size > 30000000usize {
108 return Err(ConstraintError::BlobTooLarge {
109 path: ValidationPath::from_field("snapshot"),
110 max: 30000000usize,
111 actual: size,
112 });
113 }
114 }
115 }
116 {
117 let value = &self.snapshot;
118 {
119 let mime = value.blob().mime_type.as_str();
120 let accepted: &[&str] = &["*/*"];
121 let matched = accepted
122 .iter()
123 .any(|pattern| {
124 if *pattern == "*/*" {
125 true
126 } else if pattern.ends_with("/*") {
127 let prefix = &pattern[..pattern.len() - 2];
128 mime.starts_with(prefix)
129 && mime.as_bytes().get(prefix.len()) == Some(&b'/')
130 } else {
131 mime == *pattern
132 }
133 });
134 if !matched {
135 return Err(ConstraintError::BlobMimeTypeNotAccepted {
136 path: ValidationPath::from_field("snapshot"),
137 accepted: vec!["*/*".to_string()],
138 actual: mime.to_string(),
139 });
140 }
141 }
142 }
143 Ok(())
144 }
145}
146
147pub mod root_state {
148
149 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
150 #[allow(unused)]
151 use ::core::marker::PhantomData;
152 mod sealed {
153 pub trait Sealed {}
154 }
155 pub trait State: sealed::Sealed {
157 type Doc;
158 type Snapshot;
159 }
160 pub struct Empty(());
162 impl sealed::Sealed for Empty {}
163 impl State for Empty {
164 type Doc = Unset;
165 type Snapshot = Unset;
166 }
167 pub struct SetDoc<S: State = Empty>(PhantomData<fn() -> S>);
169 impl<S: State> sealed::Sealed for SetDoc<S> {}
170 impl<S: State> State for SetDoc<S> {
171 type Doc = Set<members::doc>;
172 type Snapshot = S::Snapshot;
173 }
174 pub struct SetSnapshot<S: State = Empty>(PhantomData<fn() -> S>);
176 impl<S: State> sealed::Sealed for SetSnapshot<S> {}
177 impl<S: State> State for SetSnapshot<S> {
178 type Doc = S::Doc;
179 type Snapshot = Set<members::snapshot>;
180 }
181 #[allow(non_camel_case_types)]
183 pub mod members {
184 pub struct doc(());
186 pub struct snapshot(());
188 }
189}
190
191pub struct RootBuilder<'a, S: root_state::State> {
193 _state: PhantomData<fn() -> S>,
194 _fields: (Option<DocRef<'a>>, Option<BlobRef<'a>>),
195 _lifetime: PhantomData<&'a ()>,
196}
197
198impl<'a> Root<'a> {
199 pub fn new() -> RootBuilder<'a, root_state::Empty> {
201 RootBuilder::new()
202 }
203}
204
205impl<'a> RootBuilder<'a, root_state::Empty> {
206 pub fn new() -> Self {
208 RootBuilder {
209 _state: PhantomData,
210 _fields: (None, None),
211 _lifetime: PhantomData,
212 }
213 }
214}
215
216impl<'a, S> RootBuilder<'a, S>
217where
218 S: root_state::State,
219 S::Doc: root_state::IsUnset,
220{
221 pub fn doc(
223 mut self,
224 value: impl Into<DocRef<'a>>,
225 ) -> RootBuilder<'a, root_state::SetDoc<S>> {
226 self._fields.0 = Option::Some(value.into());
227 RootBuilder {
228 _state: PhantomData,
229 _fields: self._fields,
230 _lifetime: PhantomData,
231 }
232 }
233}
234
235impl<'a, S> RootBuilder<'a, S>
236where
237 S: root_state::State,
238 S::Snapshot: root_state::IsUnset,
239{
240 pub fn snapshot(
242 mut self,
243 value: impl Into<BlobRef<'a>>,
244 ) -> RootBuilder<'a, root_state::SetSnapshot<S>> {
245 self._fields.1 = Option::Some(value.into());
246 RootBuilder {
247 _state: PhantomData,
248 _fields: self._fields,
249 _lifetime: PhantomData,
250 }
251 }
252}
253
254impl<'a, S> RootBuilder<'a, S>
255where
256 S: root_state::State,
257 S::Doc: root_state::IsSet,
258 S::Snapshot: root_state::IsSet,
259{
260 pub fn build(self) -> Root<'a> {
262 Root {
263 doc: self._fields.0.unwrap(),
264 snapshot: self._fields.1.unwrap(),
265 extra_data: Default::default(),
266 }
267 }
268 pub fn build_with_data(
270 self,
271 extra_data: BTreeMap<
272 jacquard_common::deps::smol_str::SmolStr,
273 jacquard_common::types::value::Data<'a>,
274 >,
275 ) -> Root<'a> {
276 Root {
277 doc: self._fields.0.unwrap(),
278 snapshot: self._fields.1.unwrap(),
279 extra_data: Some(extra_data),
280 }
281 }
282}
283
284fn lexicon_doc_sh_weaver_edit_root() -> LexiconDoc<'static> {
285 #[allow(unused_imports)]
286 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
287 use jacquard_lexicon::lexicon::*;
288 use alloc::collections::BTreeMap;
289 LexiconDoc {
290 lexicon: Lexicon::Lexicon1,
291 id: CowStr::new_static("sh.weaver.edit.root"),
292 defs: {
293 let mut map = BTreeMap::new();
294 map.insert(
295 SmolStr::new_static("main"),
296 LexUserType::Record(LexRecord {
297 description: Some(
298 CowStr::new_static(
299 "The starting point for edit history on a notebook.",
300 ),
301 ),
302 key: Some(CowStr::new_static("tid")),
303 record: LexRecordRecord::Object(LexObject {
304 required: Some(
305 vec![
306 SmolStr::new_static("doc"), SmolStr::new_static("snapshot")
307 ],
308 ),
309 properties: {
310 #[allow(unused_mut)]
311 let mut map = BTreeMap::new();
312 map.insert(
313 SmolStr::new_static("doc"),
314 LexObjectProperty::Ref(LexRef {
315 r#ref: CowStr::new_static("sh.weaver.edit.defs#docRef"),
316 ..Default::default()
317 }),
318 );
319 map.insert(
320 SmolStr::new_static("snapshot"),
321 LexObjectProperty::Blob(LexBlob { ..Default::default() }),
322 );
323 map
324 },
325 ..Default::default()
326 }),
327 ..Default::default()
328 }),
329 );
330 map
331 },
332 ..Default::default()
333 }
334}