use core::fmt;
use std::{ops::Deref, str::FromStr};
use serde::{Deserialize, Serialize};
pub mod json;
pub mod json_ld;
pub use self::json_ld::JsonLd;
pub use json::Json;
use crate::Document;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Represented<D = Document> {
Json(Json<D>),
JsonLd(JsonLd<D>),
}
impl<D> Represented<D> {
pub fn new(document: D, options: Options) -> Self {
match options {
Options::Json => Self::Json(Json::new(document)),
Options::JsonLd(o) => Self::JsonLd(JsonLd::new(document, o)),
}
}
pub fn media_type(&self) -> MediaType {
match self {
Self::Json(_) => MediaType::Json,
Self::JsonLd(_) => MediaType::JsonLd,
}
}
pub fn document(&self) -> &D {
match self {
Self::Json(d) => d.document(),
Self::JsonLd(d) => d.document(),
}
}
pub fn into_document(self) -> D {
match self {
Self::Json(d) => d.into_document(),
Self::JsonLd(d) => d.into_document(),
}
}
}
impl<D: Serialize> Represented<D> {
pub fn to_bytes(&self) -> Vec<u8> {
match self {
Self::Json(d) => d.to_bytes(),
Self::JsonLd(d) => d.to_bytes(),
}
}
}
impl<D> Deref for Represented<D> {
type Target = D;
fn deref(&self) -> &Self::Target {
self.document()
}
}
#[derive(Debug, thiserror::Error)]
#[error("unknown DID document representation `{0}`")]
pub struct Unknown(pub String);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum MediaType {
#[serde(rename = "application/did+json")]
Json,
#[serde(rename = "application/did+ld+json")]
JsonLd,
}
impl MediaType {
pub fn name(&self) -> &'static str {
match self {
Self::Json => "application/did+json",
Self::JsonLd => "application/did+ld+json",
}
}
pub fn into_name(self) -> &'static str {
self.name()
}
}
impl From<MediaType> for String {
fn from(value: MediaType) -> Self {
value.name().to_owned()
}
}
impl fmt::Display for MediaType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.name().fmt(f)
}
}
impl FromStr for MediaType {
type Err = Unknown;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"application/did+json" => Ok(Self::Json),
"application/did+ld+json" => Ok(Self::JsonLd),
unknown => Err(Unknown(unknown.to_string())),
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum InvalidMediaType {
#[error(transparent)]
Unknown(Unknown),
#[error("invalid DID document media type")]
NotAString,
}
impl<'a> TryFrom<&'a [u8]> for MediaType {
type Error = InvalidMediaType;
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
match s {
b"application/did+json" => Ok(Self::Json),
b"application/did+ld+json" => Ok(Self::JsonLd),
unknown => match String::from_utf8(unknown.to_vec()) {
Ok(s) => Err(InvalidMediaType::Unknown(Unknown(s))),
Err(_) => Err(InvalidMediaType::NotAString),
},
}
}
}
pub enum Options {
Json,
JsonLd(json_ld::Options),
}
impl Options {
pub fn from_media_type(
type_: MediaType,
json_ld_options: impl FnOnce() -> json_ld::Options,
) -> Self {
match type_ {
MediaType::Json => Self::Json,
MediaType::JsonLd => Self::JsonLd(json_ld_options()),
}
}
}