//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vtc/members/vmc`. Version: `0.1`.
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`Payload`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/vtc/members/vmc/0.1",
/// "title": "Payload",
/// "type": "object",
/// "required": [
/// "vc"
/// ],
/// "properties": {
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "requestId": {
/// "description": "Optional: an approved join request this delivery also closes. When present and naming an approved request whose applicant is the delivering member, the community records the delivered credential as the reciprocal half of the join and marks the request's reciprocation complete.",
/// "type": "string",
/// "minLength": 1
/// },
/// "vc": {
/// "description": "The member-issued MembershipCredential (W3C VC). Opaque here; credentialSubject.id must be the community DID.",
/// "type": "object"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Optional: an approved join request this delivery also closes. When present and naming an approved request whose applicant is the delivering member, the community records the delivered credential as the reciprocal half of the join and marks the request's reciprocation complete.
#[serde(
rename = "requestId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub request_id: ::std::option::Option<PayloadRequestId>,
///The member-issued MembershipCredential (W3C VC). Opaque here; credentialSubject.id must be the community DID.
pub vc: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///Optional: an approved join request this delivery also closes. When present and naming an approved request whose applicant is the delivering member, the community records the delivered credential as the reciprocal half of the join and marks the request's reciprocation complete.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Optional: an approved join request this delivery also closes. When present and naming an approved request whose applicant is the delivering member, the community records the delivered credential as the reciprocal half of the join and marks the request's reciprocation complete.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadRequestId(::std::string::String);
impl ::std::ops::Deref for PayloadRequestId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadRequestId> for ::std::string::String {
fn from(value: PayloadRequestId) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadRequestId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadRequestId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadRequestId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadRequestId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadRequestId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`Response`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "type": "object",
/// "required": [
/// "memberDid",
/// "status",
/// "vmcId"
/// ],
/// "properties": {
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "memberDid": {
/// "description": "The delivering member, as proven by the transport.",
/// "type": "string",
/// "minLength": 1
/// },
/// "requestId": {
/// "description": "Echoed when the delivery also closed a join request (the request payload carried `requestId`).",
/// "type": "string",
/// "minLength": 1
/// },
/// "status": {
/// "description": "Terminal state of the delivery.",
/// "type": "string",
/// "enum": [
/// "stored"
/// ]
/// },
/// "vmcId": {
/// "description": "Identifier of the stored credential.",
/// "type": "string",
/// "minLength": 1
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The delivering member, as proven by the transport.
#[serde(rename = "memberDid")]
pub member_did: ResponseMemberDid,
///Echoed when the delivery also closed a join request (the request payload carried `requestId`).
#[serde(
rename = "requestId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub request_id: ::std::option::Option<ResponseRequestId>,
///Terminal state of the delivery.
pub status: ResponseStatus,
///Identifier of the stored credential.
#[serde(rename = "vmcId")]
pub vmc_id: ResponseVmcId,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///The delivering member, as proven by the transport.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The delivering member, as proven by the transport.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseMemberDid(::std::string::String);
impl ::std::ops::Deref for ResponseMemberDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseMemberDid> for ::std::string::String {
fn from(value: ResponseMemberDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseMemberDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseMemberDid {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseMemberDid {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseMemberDid {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ResponseMemberDid {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Echoed when the delivery also closed a join request (the request payload carried `requestId`).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Echoed when the delivery also closed a join request (the request payload carried `requestId`).",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseRequestId(::std::string::String);
impl ::std::ops::Deref for ResponseRequestId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseRequestId> for ::std::string::String {
fn from(value: ResponseRequestId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseRequestId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseRequestId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseRequestId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseRequestId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ResponseRequestId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Terminal state of the delivery.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Terminal state of the delivery.",
/// "type": "string",
/// "enum": [
/// "stored"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ResponseStatus {
#[serde(rename = "stored")]
Stored,
}
impl ::std::fmt::Display for ResponseStatus {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Stored => f.write_str("stored"),
}
}
}
impl ::std::str::FromStr for ResponseStatus {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"stored" => Ok(Self::Stored),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ResponseStatus {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseStatus {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseStatus {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Identifier of the stored credential.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Identifier of the stored credential.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseVmcId(::std::string::String);
impl ::std::ops::Deref for ResponseVmcId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseVmcId> for ::std::string::String {
fn from(value: ResponseVmcId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseVmcId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseVmcId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseVmcId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseVmcId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ResponseVmcId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct Payload {
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
request_id: ::std::result::Result<
::std::option::Option<super::PayloadRequestId>,
::std::string::String,
>,
vc: ::std::result::Result<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
::std::string::String,
>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
ext: Ok(Default::default()),
request_id: Ok(Default::default()),
vc: Err("no value supplied for vc".to_string()),
}
}
}
impl Payload {
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn request_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadRequestId>>,
T::Error: ::std::fmt::Display,
{
self.request_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for request_id: {e}"));
self
}
pub fn vc<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
>,
T::Error: ::std::fmt::Display,
{
self.vc = value
.try_into()
.map_err(|e| format!("error converting supplied value for vc: {e}"));
self
}
}
impl ::std::convert::TryFrom<Payload> for super::Payload {
type Error = super::error::ConversionError;
fn try_from(value: Payload) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
ext: value.ext?,
request_id: value.request_id?,
vc: value.vc?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
ext: Ok(value.ext),
request_id: Ok(value.request_id),
vc: Ok(value.vc),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
member_did: ::std::result::Result<super::ResponseMemberDid, ::std::string::String>,
request_id: ::std::result::Result<
::std::option::Option<super::ResponseRequestId>,
::std::string::String,
>,
status: ::std::result::Result<super::ResponseStatus, ::std::string::String>,
vmc_id: ::std::result::Result<super::ResponseVmcId, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
ext: Ok(Default::default()),
member_did: Err("no value supplied for member_did".to_string()),
request_id: Ok(Default::default()),
status: Err("no value supplied for status".to_string()),
vmc_id: Err("no value supplied for vmc_id".to_string()),
}
}
}
impl Response {
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn member_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseMemberDid>,
T::Error: ::std::fmt::Display,
{
self.member_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for member_did: {e}"));
self
}
pub fn request_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ResponseRequestId>>,
T::Error: ::std::fmt::Display,
{
self.request_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for request_id: {e}"));
self
}
pub fn status<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseStatus>,
T::Error: ::std::fmt::Display,
{
self.status = value
.try_into()
.map_err(|e| format!("error converting supplied value for status: {e}"));
self
}
pub fn vmc_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseVmcId>,
T::Error: ::std::fmt::Display,
{
self.vmc_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for vmc_id: {e}"));
self
}
}
impl ::std::convert::TryFrom<Response> for super::Response {
type Error = super::error::ConversionError;
fn try_from(value: Response) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
ext: value.ext?,
member_did: value.member_did?,
request_id: value.request_id?,
status: value.status?,
vmc_id: value.vmc_id?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
ext: Ok(value.ext),
member_did: Ok(value.member_did),
request_id: Ok(value.request_id),
status: Ok(value.status),
vmc_id: Ok(value.vmc_id),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vtc/members/vmc/0.1";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"memberDid\": {\n \"description\": \"The delivering member, as proven by the transport.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"requestId\": {\n \"description\": \"Echoed when the delivery also closed a join request (the request payload carried `requestId`).\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"status\": {\n \"description\": \"Terminal state of the delivery.\",\n \"enum\": [\n \"stored\"\n ],\n \"type\": \"string\"\n },\n \"vmcId\": {\n \"description\": \"Identifier of the stored credential.\",\n \"minLength\": 1,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"memberDid\",\n \"vmcId\",\n \"status\"\n ],\n \"title\": \"VTC Members Deliver VMC — receipt payload\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/vtc/members/vmc/0.1\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"requestId\": {\n \"description\": \"Optional: an approved join request this delivery also closes. When present and naming an approved request whose applicant is the delivering member, the community records the delivered credential as the reciprocal half of the join and marks the request's reciprocation complete.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"vc\": {\n \"description\": \"The member-issued MembershipCredential (W3C VC). Opaque here; credentialSubject.id must be the community DID.\",\n \"type\": \"object\"\n }\n },\n \"required\": [\n \"vc\"\n ],\n \"title\": \"VTC Members Deliver VMC — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vtc/members/vmc/0.1#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"memberDid\": {\n \"description\": \"The delivering member, as proven by the transport.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"requestId\": {\n \"description\": \"Echoed when the delivery also closed a join request (the request payload carried `requestId`).\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"status\": {\n \"description\": \"Terminal state of the delivery.\",\n \"enum\": [\n \"stored\"\n ],\n \"type\": \"string\"\n },\n \"vmcId\": {\n \"description\": \"Identifier of the stored credential.\",\n \"minLength\": 1,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"memberDid\",\n \"vmcId\",\n \"status\"\n ],\n \"title\": \"VTC Members Deliver VMC — receipt payload\",\n \"type\": \"object\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[
error_codes::SUBJECT_MISMATCH,
error_codes::NOT_A_MEMBER,
error_codes::INVALID_CREDENTIAL,
error_codes::REQUEST_NOT_FOUND,
error_codes::REQUEST_NOT_APPROVED,
error_codes::REQUEST_APPLICANT_MISMATCH,
];
/// One constant per extended error code this specification declares
/// (SPEC §7.3 item 9), named for its local part.
///
/// Emit these rather than a string literal: the code is read from the
/// specification, so it cannot name a code the specification never
/// declared.
pub mod error_codes {
/// `vtc/members/vmc:subjectMismatch`
///
/// The credential's `credentialSubject.id` is not this community's DID.
///
/// Declared `retryable: false`.
pub const SUBJECT_MISMATCH: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/members/vmc:subjectMismatch",
retryable: false,
};
/// `vtc/members/vmc:notAMember`
///
/// The sender is not an active member of this community.
///
/// Declared `retryable: false`.
pub const NOT_A_MEMBER: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/members/vmc:notAMember",
retryable: false,
};
/// `vtc/members/vmc:invalidCredential`
///
/// The credential does not verify, or is not a MembershipCredential.
///
/// Declared `retryable: false`.
pub const INVALID_CREDENTIAL: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/members/vmc:invalidCredential",
retryable: false,
};
/// `vtc/members/vmc:requestNotFound`
///
/// `requestId` was supplied but no join request with that id exists.
///
/// Declared `retryable: false`.
pub const REQUEST_NOT_FOUND: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/members/vmc:requestNotFound",
retryable: false,
};
/// `vtc/members/vmc:requestNotApproved`
///
/// `requestId` names a join request that is not in the approved state, so there is nothing to reciprocate.
///
/// Declared `retryable: false`.
pub const REQUEST_NOT_APPROVED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/members/vmc:requestNotApproved",
retryable: false,
};
/// `vtc/members/vmc:requestApplicantMismatch`
///
/// `requestId` names a join request whose applicant is not the delivering member.
///
/// Declared `retryable: false`.
pub const REQUEST_APPLICANT_MISMATCH: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/members/vmc:requestApplicantMismatch",
retryable: false,
};
}
#[cfg(test)]
mod conformance {
//! Round-trip tests harvested from the spec's `spec.md`,
//! plus a `rejects_invalid_examples` test for any fixtures
//! in `payload.invalid-examples.json` (validate feature).
/// Each fixture in `payload.invalid-examples.json` MUST be
/// rejected by at least one of: serde deserialization, or
/// JSON-Schema validation under the `validate` feature. The
/// fixture file documents the producer-side bug class that
/// each payload exemplifies; this generated test pins it.
#[cfg(feature = "validate")]
#[test]
fn rejects_invalid_examples() {
use crate::validate::ValidatedPayload;
let fixtures: &[(&str, &str)] = &[
("`vc` is required.", "{}"),
(
"`vc` must be a credential object, not a string.",
"{\n \"vc\": \"eyJhbGciOi...\"\n}",
),
(
"Unknown top-level member is rejected.",
"{\n \"__x__\": true,\n \"vc\": {}\n}",
),
(
"`requestId`, when present, must be a non-empty string.",
"{\n \"requestId\": \"\",\n \"vc\": {}\n}",
),
];
for (i, (note, raw)) in fixtures.iter().enumerate() {
let value: serde_json::Value = match serde_json::from_str(raw) {
Ok(v) => v,
Err(_) => continue,
};
let serde_ok = serde_json::from_value::<super::Payload>(value.clone()).is_ok();
let schema_ok = super::Payload::validate_value(&value).is_ok();
assert!(
!(serde_ok && schema_ok),
"invalid-example #{} ({:?}) was accepted by both serde and JSON Schema; \
the fixture's stated failure class is no longer caught:\n{}",
i + 1,
note,
raw
);
}
}
}