commit 64cd23e3888128e4c4dfd949d222d9af9caadc37 Author: alemi Date: Thu Mar 21 23:56:01 2024 +0100 feat: initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..011b707 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# Default to Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = tab +indent_size = 4 + +[*.rs] +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b4c9c87 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,329 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jrd" +version = "0.1.0" +dependencies = [ + "chrono", + "serde", + "serde_json", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..445498f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "jrd" +version = "0.1.0" +edition = "2021" +authors = [ "alemi " ] +description = "json resource descriptor, as specified by https://www.packetizer.com/json/jrd/" +license = "MIT" +keywords = ["json", "jrd", "web", "serialize"] +repository = "https://git.alemi.dev/jrd.git" +readme = "README.md" + +[lib] + +[dependencies] +chrono = { version = "0.4", features = ["serde"] } +serde = { version = "1.0", features = ["derive"] } + +[dev-dependencies] +serde_json = "1" diff --git a/README.md b/README.md new file mode 100644 index 0000000..fdf97ed --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# jrd +> json resource descriptor, as specified by https://www.packetizer.com/json/jrd/ + +this tiny crate provides a struct representation for Json Resource Descriptors, with serde traits derived + +get more information on its usage on [docs.rs](https://docs.rs/jrd/latest/jrd) + +## why +this crate is tiny and does very little, mostly piggy-backing from Packetizer's documentation + +i found myself writing this and the docs for myself while working on a project, to have better +hints around JRDs, so I thought others might find it useful and decided to share it publicly diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5ab7ef4 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,227 @@ +//! # JRD +//! +//! from [Packetizer](https://www.packetizer.com/json/jrd/): +//! > The JSON Resource Descriptor (JRD) is a simple [JSON](https://www.techabulary.com/j/json/) object that describes a "resource" on the Internet, +//! > where a "resource" is any entity on the Internet that is identified via a URI or IRI. +//! > For example, a person's account URI (e.g., acct:bob@example.com) is a resource. +//! > So are all web URIs (e.g., https://www.packetizer.com/). +//! +//! +//! > The JSON Resource Descriptor, originally introduced in [RFC 6415](https://www.packetizer.com/rfc/rfc6415/) and +//! > based on the Extensible Resource Descriptor (XRD) format, was adopted for use +//! > in the [WebFinger](https://www.techabulary.com/w/webfinger/) protocol, though its use is not restricted +//! > to WebFinger or RFC 6415. +//! +//! This tiny crate provides a struct representation of JRDs, [JsonResourceDescriptor], together with +//! [serde::Serialize] and [serde::Deserialize] implementations. +//! +//! All documentation is copied as-is from packetizer.com. +//! +//! # usage +//! ```rust +//! let jrd_string = r#"{ +//! "subject": "acct:paulej@packetizer.com", +//! "properties": { +//! "http://packetizer.com/ns/name": "Paul E. Jones" +//! }, +//! "links": [ +//! { +//! "rel": "http://webfinger.net/rel/profile-page", +//! "href": "http://www.packetizer.com/people/paulej/" +//! }, +//! { +//! "rel": "http://packetizer.com/rel/blog", +//! "type": "text/html", +//! "href": "http://www.packetizer.com/people/paulej/blog/", +//! "titles": { +//! "en-us": "Paul E. Jones' Blog" +//! } +//! } +//! ] +//! }"#; +//! +//! let jrd_struct = jrd::JsonResourceDescriptor { +//! subject: "acct:paulej@packetizer.com".into(), +//! aliases: Vec::new(), +//! properties: [("http://packetizer.com/ns/name".to_string(), "Paul E. Jones".to_string())].into(), +//! expires: None, +//! links: vec![ +//! jrd::JsonResourceDescriptorLink { +//! rel: "http://webfinger.net/rel/profile-page".into(), +//! href: Some("http://www.packetizer.com/people/paulej/".into()), +//! link_type: None, +//! titles: jrd::Map::default(), +//! properties: jrd::Map::default(), +//! }, +//! jrd::JsonResourceDescriptorLink { +//! rel: "http://packetizer.com/rel/blog".into(), +//! href: Some("http://www.packetizer.com/people/paulej/blog/".into()), +//! link_type: Some("text/html".into()), +//! titles: [("en-us".to_string(), "Paul E. Jones' Blog".to_string())].into(), +//! properties: jrd::Map::default(), +//! }, +//! ], +//! }; +//! +//! // deserialize +//! assert_eq!(serde_json::from_str::(jrd_string).unwrap(), jrd_struct); +//! +//! // serialize +//! assert_eq!(serde_json::to_string_pretty(&jrd_struct).unwrap(), jrd_string) +//! ``` + + +pub type Map = std::collections::BTreeMap; +pub type Time = chrono::DateTime; + + +/// The JSON Resource Descriptor (JRD) is a simple JSON object that describes a "resource" on the Internet, where a "resource" is any entity on the Internet that is identified via a URI or IRI. +/// +/// For example, a person's account URI (e.g., acct:bob@example.com) is a resource. So are all web URIs (e.g., https://www.packetizer.com/). +/// The JSON Resource Descriptor, originally introduced in [RFC 6415](https://www.packetizer.com/rfc/rfc6415/) and based on the Extensible Resource Descriptor (XRD) format, +/// was adopted for use in the WebFinger protocol, though its use is not restricted to WebFinger or [RFC 6415](https://www.packetizer.com/rfc/rfc6415/). +/// A JRD object comprises the following name/value pairs: +/// * expires +/// * subject +/// * aliases +/// * properties +/// * links +/// +/// A JRD describes a URI or IRI by returning structured information about the identifier. +/// For example, a JRD that describes a person named Paul might include information about Paul's full name, homepage, blog, etc. +/// +/// Here is an example JRD that describes a user named Paul: +/// ```json +/// { +/// "subject" : "acct:paulej@packetizer.com", +/// "properties" : +/// { +/// "http://packetizer.com/ns/name" : "Paul E. Jones" +/// }, +/// "links" : +/// [ +/// { +/// "rel" : "http://webfinger.net/rel/profile-page", +/// "href" : "http://www.packetizer.com/people/paulej/" +/// }, +/// { +/// "rel" : "http://packetizer.com/rel/blog", +/// "type" : "text/html", +/// "href" : "http://www.packetizer.com/people/paulej/blog/", +/// "titles" : +/// { +/// "en-us" : "Paul E. Jones' Blog" +/// } +/// } +/// ] +/// } +/// ``` +#[derive(Debug, Clone, Eq, PartialEq, Default, serde::Serialize, serde::Deserialize)] +pub struct JsonResourceDescriptor { + /// The value of the "subject" member is an URI that identifies the entity that the JRD describes. + /// The “subject” member SHOULD be present in the JRD. + pub subject: String, + + /// The “aliases” array is an array of zero or more URI strings that identify the same entity as the “subject” URI. + /// The “aliases” member is OPTIONAL in the JRD. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub aliases: Vec, + + /// The “properties” object comprises zero or more name/value pairs whose names are URIs (referred to as “property identifiers”) and whose values are strings or null. + /// + /// Properties are used to convey additional information about the subject of the JRD. As an example, consider this use of “properties”: + /// ```json + /// "properties" : { "http://packetizer.com/ns/name" : "Bob Smith" } + /// ``` + /// The “properties” member is optional. + #[serde(default, skip_serializing_if = "Map::is_empty")] + pub properties: Map, + + /// The value of the “expires” member is a string that indicates the date and time after which the JRD SHOULD be considered expired and no longer utilized. + /// + /// This format is formally defined in RFC 3339. The “expires” member MUST NOT use fractional seconds and MUST express time only Universal Coordinate Time via the “Z” designation on the end of the string. + /// An example of the “expires” member is: + /// ```json + /// "expires" : "2012-11-16T19:41:35Z" + /// ``` + /// + /// The “expires” member is OPTIONAL in the JRD, but should be honored if present. + /// Note: The “expires” member is not defined for use with WebFinger, but is defined for Host Metadata ([RFC 6415](https://www.packetizer.com/rfc/rfc6415/)). For WebFinger, this member MUST NOT be transmitted and ignored if received. + #[serde(skip_serializing_if = "Option::is_none")] + pub expires: Option