Skip to content

Commit

Permalink
Introduce atrium_api::types::Unknown for unknown fields
Browse files Browse the repository at this point in the history
Closes #204.
  • Loading branch information
str4d committed Jul 27, 2024
1 parent 75673d0 commit e1d4b5c
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 22 deletions.
7 changes: 7 additions & 0 deletions atrium-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- `atrium_api::types::Unknown`

### Changed
- `unknown` field types that don't have a well-known format now have the type
`atrium_api::types::Unknown` instead of `atrium_api::records::Record`.

## [0.23.2](https://github.com/sugyan/atrium/compare/atrium-api-v0.23.1...atrium-api-v0.23.2) - 2024-07-03

### Added
Expand Down
2 changes: 1 addition & 1 deletion atrium-api/src/app/bsky/embed/record.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions atrium-api/src/com/atproto/identity/sign_plc_operation.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions atrium-api/src/com/atproto/repo/apply_writes.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion atrium-api/src/com/atproto/repo/get_record.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion atrium-api/src/com/atproto/repo/list_records.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion atrium-api/src/com/atproto/server/create_account.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions atrium-api/src/tools/ozone/moderation/defs.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions atrium-api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ pub enum Union<T> {
Unknown(UnknownData),
}

/// Data with an unknown schema in an open [`Union`].
///
/// The data of variants represented by a map and include a `$type` field indicating the variant type.
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct UnknownData {
Expand All @@ -137,6 +139,30 @@ pub struct UnknownData {
pub data: Ipld,
}

/// Arbitrary data with no specific validation and no type-specific fields.
///
/// Corresponds to [the `unknown` field type].
///
/// [the `unknown` field type]: https://atproto.com/specs/lexicon#unknown
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(try_from = "Ipld")]
pub struct Unknown {
pub data: Ipld,
}

impl TryFrom<Ipld> for Unknown {
type Error = &'static str;

fn try_from(value: Ipld) -> Result<Self, Self::Error> {
// Enforce the ATProto data model.
// https://atproto.com/specs/data-model
match value {
Ipld::Float(_) => Err("Floats are not allowed in ATProto"),
data => Ok(Unknown { data }),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
29 changes: 21 additions & 8 deletions lexicon/atrium-codegen/src/token_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ fn lex_object_property(
LexObjectProperty::Boolean(boolean) => boolean_type(boolean)?,
LexObjectProperty::Integer(integer) => integer_type(integer)?,
LexObjectProperty::String(string) => string_type(string)?,
LexObjectProperty::Unknown(unknown) => unknown_type(unknown, Some(name))?,
LexObjectProperty::Unknown(unknown) => unknown_type(unknown, NamedUnknown::Field(name))?,
};
let field_name = format_ident!(
"{}",
Expand Down Expand Up @@ -401,7 +401,7 @@ fn array_type(
let (_, item_type) = match &array.items {
LexArrayItem::Integer(integer) => integer_type(integer)?,
LexArrayItem::String(string) => string_type(string)?,
LexArrayItem::Unknown(unknown) => unknown_type(unknown, None)?,
LexArrayItem::Unknown(unknown) => unknown_type(unknown, NamedUnknown::Array(name))?,
LexArrayItem::CidLink(cid_link) => cid_link_type(cid_link)?,
LexArrayItem::Ref(r#ref) => ref_type(r#ref)?,
LexArrayItem::Union(union) => union_type(
Expand Down Expand Up @@ -562,13 +562,26 @@ fn string_type(string: &LexString) -> Result<(TokenStream, TokenStream)> {
Ok((description, typ))
}

fn unknown_type(unknown: &LexUnknown, name: Option<&str>) -> Result<(TokenStream, TokenStream)> {
enum NamedUnknown<'s> {
Field(&'s str),
Array(&'s str),
}

fn unknown_type(
unknown: &LexUnknown,
name: NamedUnknown<'_>,
) -> Result<(TokenStream, TokenStream)> {
let description = description(&unknown.description);
if name == Some("didDoc") {
Ok((description, quote!(crate::did_doc::DidDocument)))
} else {
Ok((description, quote!(crate::records::Record)))
}

let typ = match name {
NamedUnknown::Field("didDoc") => quote!(crate::did_doc::DidDocument),
NamedUnknown::Field("record") | NamedUnknown::Array("relatedRecords") => {
quote!(crate::records::Record)
}
_ => quote!(crate::types::Unknown),
};

Ok((description, typ))
}

fn description(description: &Option<String>) -> TokenStream {
Expand Down

0 comments on commit e1d4b5c

Please sign in to comment.