Expand description
§Derive macros for jacquard lexicon types
This crate provides attribute and derive macros for working with Jacquard types.
The code generator uses #[lexicon] and #[open_union] to add lexicon-specific behavior.
You’ll use #[derive(IntoStatic)] frequently, #[derive(XrpcRequest)] when defining
custom XRPC endpoints, and #[derive(LexiconSchema)] for reverse codegen (Rust → lexicon).
§Macros
§#[lexicon]
Adds an extra_data field to structs to capture unknown fields during deserialization.
This makes objects “open” - they’ll accept and preserve fields not defined in the schema.
#[lexicon]
struct Post<'s> {
text: &'s str,
}
// Expands to add:
// #[serde(flatten)]
// pub extra_data: BTreeMap<SmolStr, Data<'s>>§#[open_union]
Adds an Unknown(Data) variant to enums to make them extensible unions. This lets
enums accept variants not defined in your code, storing them as loosely typed atproto Data.
#[open_union]
enum RecordEmbed<'s> {
#[serde(rename = "app.bsky.embed.images")]
Images(Images),
}
// Expands to add:
// #[serde(untagged)]
// Unknown(Data<'s>)§#[derive(IntoStatic)]
Derives conversion from borrowed ('a) to owned ('static) types by recursively calling
.into_static() on all fields. Works with structs and enums.
#[derive(IntoStatic)]
struct Post<'a> {
text: CowStr<'a>,
}
// Generates:
// impl IntoStatic for Post<'_> {
// type Output = Post<'static>;
// fn into_static(self) -> Self::Output { ... }
// }§#[derive(XrpcRequest)]
Derives XRPC request traits for custom endpoints. Generates the response marker struct
and implements XrpcRequest (and optionally XrpcEndpoint for server-side).
#[derive(Serialize, Deserialize, XrpcRequest)]
#[xrpc(
nsid = "com.example.getThing",
method = Query,
output = GetThingOutput,
)]
struct GetThing<'a> {
#[serde(borrow)]
pub id: CowStr<'a>,
}
// Generates:
// - GetThingResponse struct
// - impl XrpcResp for GetThingResponse
// - impl XrpcRequest for GetThing§#[derive(LexiconSchema)]
Derives LexiconSchema trait for reverse codegen (Rust → lexicon JSON). Generate
lexicon schemas from your Rust types for rapid prototyping and custom lexicons.
Type-level attributes (#[lexicon(...)]):
nsid = "...": The lexicon NSID (required)record: Mark as a record typekey = "...": Record key type ("tid","literal:self", or custom) - optionalobject: Mark as an object type (default if neither record/procedure/query)fragment = "...": Fragment name for non-main defs (e.g.,fragment = "textSlice")
Field-level attributes (#[lexicon(...)]):
max_length = N: Max byte length for stringsmax_graphemes = N: Max grapheme count for stringsmin_length = N,min_graphemes = N: Minimum constraintsminimum = N,maximum = N: Integer range constraintsmax_items = N: Max array lengthitem_max_length = N,item_max_graphemes = N: Constraints on array itemsref = "...": Explicit type ref (e.g.,ref = "com.atproto.repo.strongRef"orref = "#textSlice")union: Mark field as union type (use with#[lexicon_union]enum)
Serde integration: Respects #[serde(rename)], #[serde(rename_all)], and
#[serde(skip)]. Defaults to camelCase for field names (lexicon standard).
Unions: Use #[lexicon_union] attribute macro, not #[derive(LexiconSchema)].
Mark union fields with #[lexicon(union)].
// Record with constraints and fragments
#[derive(LexiconSchema)]
#[lexicon(nsid = "app.bsky.feed.post", record, key = "tid")]
#[serde(rename_all = "camelCase")]
struct Post<'a> {
#[lexicon(max_graphemes = 300, max_length = 3000)]
pub text: CowStr<'a>,
pub created_at: Datetime, // -> "createdAt" (camelCase)
#[lexicon(union)]
pub embed: Option<PostEmbed<'a>>,
#[lexicon(max_items = 8, item_max_length = 640, item_max_graphemes = 64)]
pub tags: Option<Vec<CowStr<'a>>>,
#[lexicon(ref = "app.bsky.richtext.facet")]
pub facets: Option<Vec<CowStr<'a>>>,
}
// Fragment (non-main def)
#[derive(LexiconSchema)]
#[lexicon(nsid = "app.bsky.feed.post", fragment = "textSlice")]
#[serde(rename_all = "camelCase")]
struct TextSlice {
#[lexicon(minimum = 0)]
pub start: i64,
#[lexicon(minimum = 0)]
pub end: i64,
}
// Union (uses lexicon_union, not LexiconSchema)
#[lexicon_union]
#[serde(tag = "$type")]
enum PostEmbed<'a> {
#[serde(rename = "app.bsky.embed.images")]
Images(CowStr<'a>),
#[serde(rename = "app.bsky.embed.video")]
Video(CowStr<'a>),
}Attribute Macros§
- lexicon
- Attribute macro that adds an
extra_datafield to structs to capture unknown fields during deserialization. - lexicon_
union - Attribute macro for union enums.
- open_
union - Attribute macro that adds an
Unknown(Data)variant to enums to make them open unions.
Derive Macros§
- Into
Static - Derive macro for
IntoStatictrait. - Lexicon
Schema - Derive macro for
LexiconSchematrait. - Xrpc
Request - Derive macro for
XrpcRequesttrait.