use nuts_backend::Backend;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
macro_rules! as_into_impls {
($as_name:ident + $into_name:ident => $variant:ident) => {
pub fn $as_name(&self) -> Option<()> {
match self {
Self::$variant => Some(()),
_ => None,
}
}
pub fn $into_name(self) -> Option<()> {
match self {
Self::$variant => Some(()),
_ => None,
}
}
};
($as_name:ident + $into_name:ident => $variant:ident ( $arg:ident : $type:ty )) => {
pub fn $as_name(&self) -> Option<&$type> {
match self {
Self::$variant($arg) => Some($arg),
_ => None,
}
}
pub fn $into_name(self) -> Option<$type> {
match self {
Self::$variant($arg) => Some($arg),
_ => None,
}
}
};
($as_name:ident + $into_name:ident => $variant:ident ( $( $arg:ident : $type:ty ),+ )) => {
pub fn $as_name(&self) -> Option<( $( &$type ),+)> {
match self {
Self::$variant($( $arg ),+) => Some(($( $arg ),+)),
_ => None,
}
}
pub fn $into_name(self) -> Option<( $( $type ),+)> {
match self {
Self::$variant($( $arg ),+) => Some(($( $arg ),+)),
_ => None,
}
}
};
}
struct VecDebug<'a>(&'a Vec<u8>);
#[cfg(feature = "debug-condensed")]
impl<'a> fmt::Debug for VecDebug<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "<{} bytes>", self.0.len())
}
}
#[cfg(not(feature = "debug-condensed"))]
impl<'a> fmt::Debug for VecDebug<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.0, fmt)
}
}
#[derive(Deserialize, Serialize)]
#[serde(tag = "op", content = "args", rename_all = "kebab-case")]
pub enum Request {
PluginInfo,
Settings,
IdSize,
BlockSize,
IdToBytes(String),
IdToString(Vec<u8>),
Open(Vec<u8>),
Create(Vec<u8>, bool),
Info,
Aquire(Vec<u8>),
Release(Vec<u8>),
ReadHeader,
WriteHeader(Vec<u8>),
Read(Vec<u8>),
Write(Vec<u8>, Vec<u8>),
Delete,
Quit,
}
impl Request {
as_into_impls!(as_plugin_info + into_plugin_info => PluginInfo);
as_into_impls!(as_settings + into_settings => Settings);
as_into_impls!(as_id_size + into_id_size => IdSize);
as_into_impls!(as_block_size + into_block_size => BlockSize);
as_into_impls!(as_id_to_bytes + into_id_to_bytes => IdToBytes(arg1: String));
as_into_impls!(as_id_to_string + into_id_to_string => IdToString(arg1: Vec<u8>));
as_into_impls!(as_open + into_open => Open (arg1: Vec<u8>));
as_into_impls!(as_create + into_create => Create (arg1: Vec<u8>, args: bool));
as_into_impls!(as_info + into_info => Info);
as_into_impls!(as_aquire + into_aquire => Aquire (arg1: Vec<u8>));
as_into_impls!(as_release + into_release => Release (arg1: Vec<u8>));
as_into_impls!(as_read_header + into_read_header => ReadHeader);
as_into_impls!(as_write_header + into_write_header => WriteHeader (arg1: Vec<u8>));
as_into_impls!(as_read + into_read => Read (arg1: Vec<u8>));
as_into_impls!(as_write + into_write => Write (arg1: Vec<u8>, arg2: Vec<u8>));
as_into_impls!(as_delete + into_delete => Delete);
as_into_impls!(as_quit + into_quit => Quit);
}
impl fmt::Debug for Request {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::PluginInfo => write!(fmt, "PluginInfo"),
Self::Settings => write!(fmt, "Settings"),
Self::IdSize => write!(fmt, "IdSize"),
Self::BlockSize => write!(fmt, "BlockSize"),
Self::IdToBytes(arg) => fmt.debug_tuple("IdToBytes").field(arg).finish(),
Self::IdToString(arg) => fmt.debug_tuple("IdToString").field(&VecDebug(arg)).finish(),
Self::Open(arg) => fmt.debug_tuple("Open").field(&VecDebug(arg)).finish(),
Self::Create(arg1, arg2) => fmt
.debug_tuple("Create")
.field(&VecDebug(arg1))
.field(arg2)
.finish(),
Self::Info => write!(fmt, "Info"),
Self::Aquire(arg) => fmt.debug_tuple("Aquire").field(&VecDebug(arg)).finish(),
Self::Release(arg) => fmt.debug_tuple("Release").field(&VecDebug(arg)).finish(),
Self::ReadHeader => write!(fmt, "ReadHeader"),
Self::WriteHeader(arg) => fmt
.debug_tuple("WriteHeader")
.field(&VecDebug(arg))
.finish(),
Self::Read(arg) => fmt.debug_tuple("Read").field(&VecDebug(arg)).finish(),
Self::Write(arg1, arg2) => fmt
.debug_tuple("Write")
.field(&VecDebug(arg1))
.field(&VecDebug(arg2))
.finish(),
Self::Delete => write!(fmt, "Delete"),
Self::Quit => write!(fmt, "Quit"),
}
}
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "code", content = "args", rename_all = "kebab-case")]
pub enum Response {
Ok(OkResponse),
Err(ErrorResponse),
}
impl Response {
pub fn ok_void() -> Response {
Self::Ok(OkResponse::Void)
}
pub fn ok_u32(value: u32) -> Response {
Self::Ok(OkResponse::U32(value))
}
pub fn ok_usize(value: usize) -> Response {
Self::Ok(OkResponse::Usize(value))
}
pub fn ok_bytes(value: Vec<u8>) -> Response {
Self::Ok(OkResponse::Bytes(value))
}
pub fn ok_string(value: String) -> Response {
Self::Ok(OkResponse::String(value))
}
pub fn ok_map(value: HashMap<String, String>) -> Response {
Self::Ok(OkResponse::Map(value))
}
pub fn err_not_applicable() -> Response {
Self::Err(ErrorResponse::NotApplicable)
}
pub fn err_message<M: AsRef<str>>(msg: M) -> Response {
Self::Err(ErrorResponse::Message(msg.as_ref().to_string()))
}
as_into_impls!(as_ok + into_ok => Ok (ok: OkResponse));
as_into_impls!(as_error + into_error => Err (err: ErrorResponse));
}
#[derive(Deserialize, Serialize)]
#[serde(tag = "type", content = "args", rename_all = "kebab-case")]
pub enum OkResponse {
Void,
U32(u32),
Usize(usize),
Bytes(Vec<u8>),
String(String),
Map(HashMap<String, String>),
}
impl fmt::Debug for OkResponse {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Void => write!(fmt, "Void"),
Self::U32(arg) => fmt.debug_tuple("U32").field(arg).finish(),
Self::Usize(arg) => fmt.debug_tuple("Usize").field(arg).finish(),
Self::Bytes(arg) => fmt.debug_tuple("Bytes").field(&VecDebug(arg)).finish(),
Self::String(arg) => fmt.debug_tuple("String").field(arg).finish(),
Self::Map(arg) => fmt.debug_tuple("Map").field(arg).finish(),
}
}
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "code", content = "args", rename_all = "kebab-case")]
pub enum ErrorResponse {
NotApplicable,
InvalidId,
InvalidIdData,
InvalidSettingsData,
InvalidInfo,
InvalidHeaderBytes,
Backend(String),
Message(String),
}
impl ErrorResponse {
pub fn message<T: AsRef<str>>(msg: T) -> ErrorResponse {
Self::Message(msg.as_ref().to_string())
}
pub fn backend<B: Backend>(err: B::Err) -> ErrorResponse {
Self::Backend(err.to_string())
}
}
impl fmt::Display for ErrorResponse {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::NotApplicable => write!(fmt, "the call is not applicable"),
Self::InvalidId => write!(fmt, "could not parse id"),
Self::InvalidIdData => write!(fmt, "could not create id"),
Self::InvalidSettingsData => write!(fmt, "could not create settings"),
Self::InvalidInfo => write!(fmt, "could not collect backend information"),
Self::InvalidHeaderBytes => write!(fmt, "invalid header bytes"),
Self::Backend(msg) => write!(fmt, "the backend created an error: {}", msg),
Self::Message(msg) => write!(fmt, "{}", msg),
}
}
}