···22pub mod cowstr;
33#[macro_use]
44pub mod into_static;
55-55+pub mod macros;
66pub mod types;
7788pub use cowstr::CowStr;
99pub use into_static::IntoStatic;
1010-1110pub use smol_str;
1211pub use url;
+288
crates/jacquard-common/src/macros.rs
···11+//! `atproto!` macro.
22+/// Construct a atproto `Data<'_>` value from a literal.
33+///
44+/// ```
55+/// # use jacquard_common::atproto;
66+/// #
77+/// let value = atproto!({
88+/// "code": 200,
99+/// "success": true,
1010+/// "payload": {
1111+/// "features": [
1212+/// "serde",
1313+/// "json"
1414+/// ]
1515+/// }
1616+/// });
1717+/// ```
1818+///
1919+/// Variables or expressions can be interpolated into the ATProto literal. Any type
2020+/// interpolated into an array element or object value must implement Serde's
2121+/// `Serialize` trait, while any type interpolated into a object key must
2222+/// implement `Into<String>`. If the `Serialize` implementation of the
2323+/// interpolated type decides to fail, or if the interpolated type contains a
2424+/// map with non-string keys, the `atproto!` macro will panic.
2525+///
2626+/// ```
2727+/// # use jacquard_common::atproto;
2828+/// #
2929+/// let code = 200;
3030+/// let features = vec!["serde", "json"];
3131+///
3232+/// let value = atproto!({
3333+/// "code": code,
3434+/// "success": code == 200,
3535+/// "payload": {
3636+/// features[0]: features[1]
3737+/// }
3838+/// });
3939+/// ```
4040+///
4141+/// Trailing commas are allowed inside both arrays and objects.
4242+///
4343+/// ```
4444+/// # use jacquard_common::atproto;
4545+/// #
4646+/// let value = atproto!([
4747+/// "notice",
4848+/// "the",
4949+/// "trailing",
5050+/// "comma -->",
5151+/// ]);
5252+/// ```
5353+#[macro_export(local_inner_macros)]
5454+macro_rules! atproto {
5555+ // Hide distracting implementation details from the generated rustdoc.
5656+ ($($atproto:tt)+) => {
5757+ atproto_internal!($($atproto)+)
5858+ };
5959+}
6060+6161+#[macro_export(local_inner_macros)]
6262+#[doc(hidden)]
6363+macro_rules! atproto_internal {
6464+ //////////////////////////////////////////////////////////////////////////
6565+ // TT muncher for parsing the inside of an array [...]. Produces a vec![...]
6666+ // of the elements.
6767+ //
6868+ // Must be invoked as: atproto_internal!(@array [] $($tt)*)
6969+ //////////////////////////////////////////////////////////////////////////
7070+7171+ // Done with trailing comma.
7272+ (@array [$($elems:expr,)*]) => {
7373+ atproto_internal_vec![$($elems,)*]
7474+ };
7575+7676+ // Done without trailing comma.
7777+ (@array [$($elems:expr),*]) => {
7878+ atproto_internal_vec![$($elems),*]
7979+ };
8080+8181+ // Next element is `null`.
8282+ (@array [$($elems:expr,)*] null $($rest:tt)*) => {
8383+ atproto_internal!(@array [$($elems,)* atproto_internal!(null)] $($rest)*)
8484+ };
8585+8686+ // Next element is `true`.
8787+ (@array [$($elems:expr,)*] true $($rest:tt)*) => {
8888+ atproto_internal!(@array [$($elems,)* atproto_internal!(true)] $($rest)*)
8989+ };
9090+9191+ // Next element is `false`.
9292+ (@array [$($elems:expr,)*] false $($rest:tt)*) => {
9393+ atproto_internal!(@array [$($elems,)* atproto_internal!(false)] $($rest)*)
9494+ };
9595+9696+ // Next element is an array.
9797+ (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
9898+ atproto_internal!(@array [$($elems,)* atproto_internal!([$($array)*])] $($rest)*)
9999+ };
100100+101101+ // Next element is a map.
102102+ (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
103103+ atproto_internal!(@array [$($elems,)* atproto_internal!({$($map)*})] $($rest)*)
104104+ };
105105+106106+ // Next element is an expression followed by comma.
107107+ (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
108108+ atproto_internal!(@array [$($elems,)* atproto_internal!($next),] $($rest)*)
109109+ };
110110+111111+ // Last element is an expression with no trailing comma.
112112+ (@array [$($elems:expr,)*] $last:expr) => {
113113+ atproto_internal!(@array [$($elems,)* atproto_internal!($last)])
114114+ };
115115+116116+ // Comma after the most recent element.
117117+ (@array [$($elems:expr),*] , $($rest:tt)*) => {
118118+ atproto_internal!(@array [$($elems,)*] $($rest)*)
119119+ };
120120+121121+ // Unexpected token after most recent element.
122122+ (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
123123+ atproto_unexpected!($unexpected)
124124+ };
125125+126126+ //////////////////////////////////////////////////////////////////////////
127127+ // TT muncher for parsing the inside of an object {...}. Each entry is
128128+ // inserted into the given map variable.
129129+ //
130130+ // Must be invoked as: atproto_internal!(@object $map () ($($tt)*) ($($tt)*))
131131+ //
132132+ // We require two copies of the input tokens so that we can match on one
133133+ // copy and trigger errors on the other copy.
134134+ //////////////////////////////////////////////////////////////////////////
135135+136136+ // Done.
137137+ (@object $object:ident () () ()) => {};
138138+139139+ // Insert the current entry followed by trailing comma.
140140+ (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
141141+ let _ = $object.insert(($($key)+).into(), $value);
142142+ atproto_internal!(@object $object () ($($rest)*) ($($rest)*));
143143+ };
144144+145145+ // Current entry followed by unexpected token.
146146+ (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
147147+ atproto_unexpected!($unexpected);
148148+ };
149149+150150+ // Insert the last entry without trailing comma.
151151+ (@object $object:ident [$($key:tt)+] ($value:expr)) => {
152152+ let _ = $object.insert(($($key)+).into(), $value);
153153+ };
154154+155155+ // Next value is `null`.
156156+ (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
157157+ atproto_internal!(@object $object [$($key)+] (atproto_internal!(null)) $($rest)*);
158158+ };
159159+160160+ // Next value is `true`.
161161+ (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => {
162162+ atproto_internal!(@object $object [$($key)+] (atproto_internal!(true)) $($rest)*);
163163+ };
164164+165165+ // Next value is `false`.
166166+ (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => {
167167+ atproto_internal!(@object $object [$($key)+] (atproto_internal!(false)) $($rest)*);
168168+ };
169169+170170+ // Next value is an array.
171171+ (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
172172+ atproto_internal!(@object $object [$($key)+] (atproto_internal!([$($array)*])) $($rest)*);
173173+ };
174174+175175+ // Next value is a map.
176176+ (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
177177+ atproto_internal!(@object $object [$($key)+] (atproto_internal!({$($map)*})) $($rest)*);
178178+ };
179179+180180+ // Next value is an expression followed by comma.
181181+ (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
182182+ atproto_internal!(@object $object [$($key)+] (atproto_internal!($value)) , $($rest)*);
183183+ };
184184+185185+ // Last value is an expression with no trailing comma.
186186+ (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
187187+ atproto_internal!(@object $object [$($key)+] (atproto_internal!($value)));
188188+ };
189189+190190+ // Missing value for last entry. Trigger a reasonable error message.
191191+ (@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
192192+ // "unexpected end of macro invocation"
193193+ atproto_internal!();
194194+ };
195195+196196+ // Missing colon and value for last entry. Trigger a reasonable error
197197+ // message.
198198+ (@object $object:ident ($($key:tt)+) () $copy:tt) => {
199199+ // "unexpected end of macro invocation"
200200+ atproto_internal!();
201201+ };
202202+203203+ // Misplaced colon. Trigger a reasonable error message.
204204+ (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
205205+ // Takes no arguments so "no rules expected the token `:`".
206206+ atproto_unexpected!($colon);
207207+ };
208208+209209+ // Found a comma inside a key. Trigger a reasonable error message.
210210+ (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
211211+ // Takes no arguments so "no rules expected the token `,`".
212212+ atproto_unexpected!($comma);
213213+ };
214214+215215+ // Key is fully parenthesized. This avoids clippy double_parens false
216216+ // positives because the parenthesization may be necessary here.
217217+ (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
218218+ atproto_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*));
219219+ };
220220+221221+ // Munch a token into the current key.
222222+ (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
223223+ atproto_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*));
224224+ };
225225+226226+ //////////////////////////////////////////////////////////////////////////
227227+ // The main implementation.
228228+ //
229229+ // Must be invoked as: atproto_internal!($($atproto)+)
230230+ //////////////////////////////////////////////////////////////////////////
231231+232232+ (null) => {
233233+ $crate::types::value::Data::Null
234234+ };
235235+236236+ (true) => {
237237+ $crate::types::value::Data::Boolean(true)
238238+ };
239239+240240+ (false) => {
241241+ $crate::types::value::Data::Boolean(false)
242242+ };
243243+244244+ ([]) => {
245245+ $crate::types::value::Data::Array($crate::types::value::Array(atproto_internal_vec![]))
246246+ };
247247+248248+ ([ $($tt:tt)+ ]) => {
249249+ $crate::types::value::Data::Array($crate::types::value::Array(atproto_internal!(@array [] $($tt)+)))
250250+ };
251251+252252+ ({}) => {
253253+ $crate::types::value::Data::Object($crate::types::value::Object(::std::collections::BTreeMap::new()))
254254+ };
255255+256256+ ({ $($tt:tt)+ }) => {
257257+ $crate::types::value::Data::Object($crate::types::value::Object({
258258+ let mut object = ::std::collections::BTreeMap::new();
259259+ atproto_internal!(@object object () ($($tt)+) ($($tt)+));
260260+ object
261261+ }))
262262+ };
263263+264264+ // Any Serialize type: numbers, strings, struct literals, variables etc.
265265+ // Must be below every other rule.
266266+ ($other:expr) => {
267267+ {
268268+ $crate::types::value::Data::from($other)
269269+ }
270270+ };
271271+}
272272+273273+// The atproto_internal macro above cannot invoke vec directly because it uses
274274+// local_inner_macros. A vec invocation there would resolve to $crate::vec.
275275+// Instead invoke vec here outside of local_inner_macros.
276276+#[macro_export]
277277+#[doc(hidden)]
278278+macro_rules! atproto_internal_vec {
279279+ ($($content:tt)*) => {
280280+ ::std::vec![$($content)*]
281281+ };
282282+}
283283+284284+#[macro_export]
285285+#[doc(hidden)]
286286+macro_rules! atproto_unexpected {
287287+ () => {};
288288+}
+4-1
crates/jacquard-common/src/types/cid.rs
···414414 fn cidlink_serialize_json() {
415415 let link = CidLink::str(TEST_CID);
416416 let json = serde_json::to_string(&link).unwrap();
417417- assert_eq!(json, r#"{"$link":"bafyreih4g7bvo6hdq2juolev5bfzpbo4ewkxh5mzxwgvkjp3kitc6hqkha"}"#);
417417+ assert_eq!(
418418+ json,
419419+ r#"{"$link":"bafyreih4g7bvo6hdq2juolev5bfzpbo4ewkxh5mzxwgvkjp3kitc6hqkha"}"#
420420+ );
418421 }
419422420423 #[test]