1#[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::collection::{Collection, RecordError};
18use jacquard_common::types::string::{AtUri, Cid, Datetime};
19use jacquard_common::types::uri::{RecordUri, UriError};
20use jacquard_common::xrpc::XrpcResp;
21use jacquard_derive::{IntoStatic, lexicon};
22use jacquard_lexicon::lexicon::LexiconDoc;
23use jacquard_lexicon::schema::LexiconSchema;
24
25#[allow(unused_imports)]
26use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
27use serde::{Serialize, Deserialize};
28
29#[lexicon]
30#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
31#[serde(rename_all = "camelCase", rename = "sh.tangled.string", tag = "$type")]
32pub struct TangledString<'a> {
33 #[serde(borrow)]
34 pub contents: CowStr<'a>,
35 pub created_at: Datetime,
36 #[serde(borrow)]
37 pub description: CowStr<'a>,
38 #[serde(borrow)]
39 pub filename: CowStr<'a>,
40}
41
42#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
45#[serde(rename_all = "camelCase")]
46pub struct TangledStringGetRecordOutput<'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: TangledString<'a>,
54}
55
56impl<'a> TangledString<'a> {
57 pub fn uri(
58 uri: impl Into<CowStr<'a>>,
59 ) -> Result<RecordUri<'a, TangledStringRecord>, UriError> {
60 RecordUri::try_from_uri(AtUri::new_cow(uri.into())?)
61 }
62}
63
64#[derive(Debug, Serialize, Deserialize)]
67pub struct TangledStringRecord;
68impl XrpcResp for TangledStringRecord {
69 const NSID: &'static str = "sh.tangled.string";
70 const ENCODING: &'static str = "application/json";
71 type Output<'de> = TangledStringGetRecordOutput<'de>;
72 type Err<'de> = RecordError<'de>;
73}
74
75impl From<TangledStringGetRecordOutput<'_>> for TangledString<'_> {
76 fn from(output: TangledStringGetRecordOutput<'_>) -> Self {
77 use jacquard_common::IntoStatic;
78 output.value.into_static()
79 }
80}
81
82impl Collection for TangledString<'_> {
83 const NSID: &'static str = "sh.tangled.string";
84 type Record = TangledStringRecord;
85}
86
87impl Collection for TangledStringRecord {
88 const NSID: &'static str = "sh.tangled.string";
89 type Record = TangledStringRecord;
90}
91
92impl<'a> LexiconSchema for TangledString<'a> {
93 fn nsid() -> &'static str {
94 "sh.tangled.string"
95 }
96 fn def_name() -> &'static str {
97 "main"
98 }
99 fn lexicon_doc() -> LexiconDoc<'static> {
100 lexicon_doc_sh_tangled_string()
101 }
102 fn validate(&self) -> Result<(), ConstraintError> {
103 {
104 let value = &self.contents;
105 {
106 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
107 if count < 1usize {
108 return Err(ConstraintError::MinGraphemes {
109 path: ValidationPath::from_field("contents"),
110 min: 1usize,
111 actual: count,
112 });
113 }
114 }
115 }
116 {
117 let value = &self.description;
118 {
119 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
120 if count > 280usize {
121 return Err(ConstraintError::MaxGraphemes {
122 path: ValidationPath::from_field("description"),
123 max: 280usize,
124 actual: count,
125 });
126 }
127 }
128 }
129 {
130 let value = &self.filename;
131 {
132 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
133 if count > 140usize {
134 return Err(ConstraintError::MaxGraphemes {
135 path: ValidationPath::from_field("filename"),
136 max: 140usize,
137 actual: count,
138 });
139 }
140 }
141 }
142 {
143 let value = &self.filename;
144 {
145 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
146 if count < 1usize {
147 return Err(ConstraintError::MinGraphemes {
148 path: ValidationPath::from_field("filename"),
149 min: 1usize,
150 actual: count,
151 });
152 }
153 }
154 }
155 Ok(())
156 }
157}
158
159pub mod tangled_string_state {
160
161 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
162 #[allow(unused)]
163 use ::core::marker::PhantomData;
164 mod sealed {
165 pub trait Sealed {}
166 }
167 pub trait State: sealed::Sealed {
169 type Description;
170 type Filename;
171 type CreatedAt;
172 type Contents;
173 }
174 pub struct Empty(());
176 impl sealed::Sealed for Empty {}
177 impl State for Empty {
178 type Description = Unset;
179 type Filename = Unset;
180 type CreatedAt = Unset;
181 type Contents = Unset;
182 }
183 pub struct SetDescription<S: State = Empty>(PhantomData<fn() -> S>);
185 impl<S: State> sealed::Sealed for SetDescription<S> {}
186 impl<S: State> State for SetDescription<S> {
187 type Description = Set<members::description>;
188 type Filename = S::Filename;
189 type CreatedAt = S::CreatedAt;
190 type Contents = S::Contents;
191 }
192 pub struct SetFilename<S: State = Empty>(PhantomData<fn() -> S>);
194 impl<S: State> sealed::Sealed for SetFilename<S> {}
195 impl<S: State> State for SetFilename<S> {
196 type Description = S::Description;
197 type Filename = Set<members::filename>;
198 type CreatedAt = S::CreatedAt;
199 type Contents = S::Contents;
200 }
201 pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
203 impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
204 impl<S: State> State for SetCreatedAt<S> {
205 type Description = S::Description;
206 type Filename = S::Filename;
207 type CreatedAt = Set<members::created_at>;
208 type Contents = S::Contents;
209 }
210 pub struct SetContents<S: State = Empty>(PhantomData<fn() -> S>);
212 impl<S: State> sealed::Sealed for SetContents<S> {}
213 impl<S: State> State for SetContents<S> {
214 type Description = S::Description;
215 type Filename = S::Filename;
216 type CreatedAt = S::CreatedAt;
217 type Contents = Set<members::contents>;
218 }
219 #[allow(non_camel_case_types)]
221 pub mod members {
222 pub struct description(());
224 pub struct filename(());
226 pub struct created_at(());
228 pub struct contents(());
230 }
231}
232
233pub struct TangledStringBuilder<'a, S: tangled_string_state::State> {
235 _state: PhantomData<fn() -> S>,
236 _fields: (
237 Option<CowStr<'a>>,
238 Option<Datetime>,
239 Option<CowStr<'a>>,
240 Option<CowStr<'a>>,
241 ),
242 _lifetime: PhantomData<&'a ()>,
243}
244
245impl<'a> TangledString<'a> {
246 pub fn new() -> TangledStringBuilder<'a, tangled_string_state::Empty> {
248 TangledStringBuilder::new()
249 }
250}
251
252impl<'a> TangledStringBuilder<'a, tangled_string_state::Empty> {
253 pub fn new() -> Self {
255 TangledStringBuilder {
256 _state: PhantomData,
257 _fields: (None, None, None, None),
258 _lifetime: PhantomData,
259 }
260 }
261}
262
263impl<'a, S> TangledStringBuilder<'a, S>
264where
265 S: tangled_string_state::State,
266 S::Contents: tangled_string_state::IsUnset,
267{
268 pub fn contents(
270 mut self,
271 value: impl Into<CowStr<'a>>,
272 ) -> TangledStringBuilder<'a, tangled_string_state::SetContents<S>> {
273 self._fields.0 = Option::Some(value.into());
274 TangledStringBuilder {
275 _state: PhantomData,
276 _fields: self._fields,
277 _lifetime: PhantomData,
278 }
279 }
280}
281
282impl<'a, S> TangledStringBuilder<'a, S>
283where
284 S: tangled_string_state::State,
285 S::CreatedAt: tangled_string_state::IsUnset,
286{
287 pub fn created_at(
289 mut self,
290 value: impl Into<Datetime>,
291 ) -> TangledStringBuilder<'a, tangled_string_state::SetCreatedAt<S>> {
292 self._fields.1 = Option::Some(value.into());
293 TangledStringBuilder {
294 _state: PhantomData,
295 _fields: self._fields,
296 _lifetime: PhantomData,
297 }
298 }
299}
300
301impl<'a, S> TangledStringBuilder<'a, S>
302where
303 S: tangled_string_state::State,
304 S::Description: tangled_string_state::IsUnset,
305{
306 pub fn description(
308 mut self,
309 value: impl Into<CowStr<'a>>,
310 ) -> TangledStringBuilder<'a, tangled_string_state::SetDescription<S>> {
311 self._fields.2 = Option::Some(value.into());
312 TangledStringBuilder {
313 _state: PhantomData,
314 _fields: self._fields,
315 _lifetime: PhantomData,
316 }
317 }
318}
319
320impl<'a, S> TangledStringBuilder<'a, S>
321where
322 S: tangled_string_state::State,
323 S::Filename: tangled_string_state::IsUnset,
324{
325 pub fn filename(
327 mut self,
328 value: impl Into<CowStr<'a>>,
329 ) -> TangledStringBuilder<'a, tangled_string_state::SetFilename<S>> {
330 self._fields.3 = Option::Some(value.into());
331 TangledStringBuilder {
332 _state: PhantomData,
333 _fields: self._fields,
334 _lifetime: PhantomData,
335 }
336 }
337}
338
339impl<'a, S> TangledStringBuilder<'a, S>
340where
341 S: tangled_string_state::State,
342 S::Description: tangled_string_state::IsSet,
343 S::Filename: tangled_string_state::IsSet,
344 S::CreatedAt: tangled_string_state::IsSet,
345 S::Contents: tangled_string_state::IsSet,
346{
347 pub fn build(self) -> TangledString<'a> {
349 TangledString {
350 contents: self._fields.0.unwrap(),
351 created_at: self._fields.1.unwrap(),
352 description: self._fields.2.unwrap(),
353 filename: self._fields.3.unwrap(),
354 extra_data: Default::default(),
355 }
356 }
357 pub fn build_with_data(
359 self,
360 extra_data: BTreeMap<
361 jacquard_common::deps::smol_str::SmolStr,
362 jacquard_common::types::value::Data<'a>,
363 >,
364 ) -> TangledString<'a> {
365 TangledString {
366 contents: self._fields.0.unwrap(),
367 created_at: self._fields.1.unwrap(),
368 description: self._fields.2.unwrap(),
369 filename: self._fields.3.unwrap(),
370 extra_data: Some(extra_data),
371 }
372 }
373}
374
375fn lexicon_doc_sh_tangled_string() -> LexiconDoc<'static> {
376 #[allow(unused_imports)]
377 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
378 use jacquard_lexicon::lexicon::*;
379 use alloc::collections::BTreeMap;
380 LexiconDoc {
381 lexicon: Lexicon::Lexicon1,
382 id: CowStr::new_static("sh.tangled.string"),
383 defs: {
384 let mut map = BTreeMap::new();
385 map.insert(
386 SmolStr::new_static("main"),
387 LexUserType::Record(LexRecord {
388 key: Some(CowStr::new_static("tid")),
389 record: LexRecordRecord::Object(LexObject {
390 required: Some(
391 vec![
392 SmolStr::new_static("filename"),
393 SmolStr::new_static("description"),
394 SmolStr::new_static("createdAt"),
395 SmolStr::new_static("contents")
396 ],
397 ),
398 properties: {
399 #[allow(unused_mut)]
400 let mut map = BTreeMap::new();
401 map.insert(
402 SmolStr::new_static("contents"),
403 LexObjectProperty::String(LexString {
404 min_graphemes: Some(1usize),
405 ..Default::default()
406 }),
407 );
408 map.insert(
409 SmolStr::new_static("createdAt"),
410 LexObjectProperty::String(LexString {
411 format: Some(LexStringFormat::Datetime),
412 ..Default::default()
413 }),
414 );
415 map.insert(
416 SmolStr::new_static("description"),
417 LexObjectProperty::String(LexString {
418 max_graphemes: Some(280usize),
419 ..Default::default()
420 }),
421 );
422 map.insert(
423 SmolStr::new_static("filename"),
424 LexObjectProperty::String(LexString {
425 min_graphemes: Some(1usize),
426 max_graphemes: Some(140usize),
427 ..Default::default()
428 }),
429 );
430 map
431 },
432 ..Default::default()
433 }),
434 ..Default::default()
435 }),
436 );
437 map
438 },
439 ..Default::default()
440 }
441}