1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
/// Custom encode/decode functions.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CustomCodec {
/// Custom encode function.
///
/// Assumed to be of a type equivalent to:
///
/// `fn<T, W: Write>(&T, &mut Encoder<W>) -> Result<(), Error<W::Error>>`
///
/// Declared with `#[cbor(encode_with = "...")]`.
///
/// In addition, an optional custom `is_nil` function can be declared which
/// is assumed to be of a type equivalent to:
///
/// `fn<T>(&T) -> bool`
///
/// Declared with `#[cbor(is_nil = "...")]`
Encode(Encode),
/// Custom decode function.
///
/// Assumed to be of a type equivalent to:
///
/// `fn<T>(&mut Decoder<'_>) -> Result<T, Error>`
///
/// Declared with `#[cbor(decode_with = "...")]`.
///
/// In addition, an optional custom `nil` function can be declared which
/// is assumed to be of a type equivalent to:
///
/// `fn<T>() -> Option<T>`
///
/// Declared with `#[cbor(nil = "...")]`
Decode(Decode),
/// The combination of `encode_with` + `is_nil` and `decode_with` + `nil`.
Both(Box<Encode>, Box<Decode>),
/// A module which contains custom encode/decode functions.
///
/// The module is assumed to contain two functions named `encode` and
/// `decode` whose types match those declared with
/// `#[cbor(encode_with = "...")]` or `#[cbor(decode_with = "...")]`
/// respectively. Declared with `#[cbor(with = "...")]`.
///
/// Optionally, the attribute `has_nil` can be added which means that
/// the module contains functions `is_nil` and `nil` matching those
/// declared with `is_nil` and `nil` when using `encode_with` and
/// `decode_with`.
Module(syn::ExprPath, bool)
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Encode {
pub encode: syn::ExprPath,
pub is_nil: Option<syn::ExprPath>
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Decode {
pub decode: syn::ExprPath,
pub nil: Option<syn::ExprPath>
}
impl CustomCodec {
/// Is this a custom codec from `encode_with` or `with`?
pub fn is_encode(&self) -> bool {
!matches!(self, CustomCodec::Decode(_))
}
/// Is this a custom codec from `decode_with` or `with`?
pub fn is_decode(&self) -> bool {
!matches!(self, CustomCodec::Encode(_))
}
/// Extract the encode function unless this `CustomCodec` does not declare one.
pub fn to_encode_path(&self) -> Option<syn::ExprPath> {
match self {
CustomCodec::Encode(e) => Some(e.encode.clone()),
CustomCodec::Both(e, _) => Some(e.encode.clone()),
CustomCodec::Decode(_) => None,
CustomCodec::Module(p, _) => {
let mut p = p.clone();
let ident = syn::Ident::new("encode", proc_macro2::Span::call_site());
p.path.segments.push(ident.into());
Some(p)
}
}
}
/// Extract the decode function unless this `CustomCodec` does not declare one.
pub fn to_decode_path(&self) -> Option<syn::ExprPath> {
match self {
CustomCodec::Decode(d) => Some(d.decode.clone()),
CustomCodec::Both(_, d) => Some(d.decode.clone()),
CustomCodec::Encode(_) => None,
CustomCodec::Module(p, _) => {
let mut p = p.clone();
let ident = syn::Ident::new("decode", proc_macro2::Span::call_site());
p.path.segments.push(ident.into());
Some(p)
}
}
}
/// Extract the `is_nil` function if possible.
pub fn to_is_nil_path(&self) -> Option<syn::ExprPath> {
match self {
CustomCodec::Encode(e) => e.is_nil.clone(),
CustomCodec::Both(e, _) => e.is_nil.clone(),
CustomCodec::Module(p, true) => {
let mut p = p.clone();
let ident = syn::Ident::new("is_nil", proc_macro2::Span::call_site());
p.path.segments.push(ident.into());
Some(p)
}
CustomCodec::Module(_, false) => None,
CustomCodec::Decode(_) => None
}
}
/// Extract the `nil` function if possible.
pub fn to_nil_path(&self) -> Option<syn::ExprPath> {
match self {
CustomCodec::Decode(d) => d.nil.clone(),
CustomCodec::Both(_, d) => d.nil.clone(),
CustomCodec::Module(p, true) => {
let mut p = p.clone();
let ident = syn::Ident::new("nil", proc_macro2::Span::call_site());
p.path.segments.push(ident.into());
Some(p)
}
CustomCodec::Module(_, false) => None,
CustomCodec::Encode(_) => None
}
}
}