feat: custom option getter
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
16
crates/ptp/cursor/Cargo.lock
generated
Normal file
16
crates/ptp/cursor/Cargo.lock
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "ptp_cursor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
7
crates/ptp/cursor/Cargo.toml
Normal file
7
crates/ptp/cursor/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "ptp_cursor"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
byteorder = { version = "1.5.0" }
|
264
crates/ptp/cursor/src/lib.rs
Normal file
264
crates/ptp/cursor/src/lib.rs
Normal file
@@ -0,0 +1,264 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::redundant_closure_for_method_calls)]
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use std::io::{self, Cursor};
|
||||
|
||||
pub trait Read: ReadBytesExt {
|
||||
fn read_ptp_u8(&mut self) -> io::Result<u8> {
|
||||
self.read_u8()
|
||||
}
|
||||
|
||||
fn read_ptp_i8(&mut self) -> io::Result<i8> {
|
||||
self.read_i8()
|
||||
}
|
||||
|
||||
fn read_ptp_u16(&mut self) -> io::Result<u16> {
|
||||
self.read_u16::<LittleEndian>()
|
||||
}
|
||||
|
||||
fn read_ptp_i16(&mut self) -> io::Result<i16> {
|
||||
self.read_i16::<LittleEndian>()
|
||||
}
|
||||
|
||||
fn read_ptp_u32(&mut self) -> io::Result<u32> {
|
||||
self.read_u32::<LittleEndian>()
|
||||
}
|
||||
|
||||
fn read_ptp_i32(&mut self) -> io::Result<i32> {
|
||||
self.read_i32::<LittleEndian>()
|
||||
}
|
||||
|
||||
fn read_ptp_u64(&mut self) -> io::Result<u64> {
|
||||
self.read_u64::<LittleEndian>()
|
||||
}
|
||||
|
||||
fn read_ptp_i64(&mut self) -> io::Result<i64> {
|
||||
self.read_i64::<LittleEndian>()
|
||||
}
|
||||
|
||||
fn read_ptp_vec<T, F>(&mut self, func: F) -> io::Result<Vec<T>>
|
||||
where
|
||||
F: Fn(&mut Self) -> io::Result<T>,
|
||||
{
|
||||
let len = self.read_u32::<LittleEndian>()? as usize;
|
||||
(0..len).map(|_| func(self)).collect()
|
||||
}
|
||||
|
||||
fn read_ptp_u8_vec(&mut self) -> io::Result<Vec<u8>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_u8())
|
||||
}
|
||||
|
||||
fn read_ptp_i8_vec(&mut self) -> io::Result<Vec<i8>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_i8())
|
||||
}
|
||||
|
||||
fn read_ptp_u16_vec(&mut self) -> io::Result<Vec<u16>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_u16())
|
||||
}
|
||||
|
||||
fn read_ptp_i16_vec(&mut self) -> io::Result<Vec<i16>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_i16())
|
||||
}
|
||||
|
||||
fn read_ptp_u32_vec(&mut self) -> io::Result<Vec<u32>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_u32())
|
||||
}
|
||||
|
||||
fn read_ptp_i32_vec(&mut self) -> io::Result<Vec<i32>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_i32())
|
||||
}
|
||||
|
||||
fn read_ptp_u64_vec(&mut self) -> io::Result<Vec<u64>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_u64())
|
||||
}
|
||||
|
||||
fn read_ptp_i64_vec(&mut self) -> io::Result<Vec<i64>> {
|
||||
self.read_ptp_vec(|cur| cur.read_ptp_i64())
|
||||
}
|
||||
|
||||
fn read_ptp_str(&mut self) -> io::Result<String> {
|
||||
let len = self.read_u8()?;
|
||||
if len == 0 {
|
||||
return Ok(String::new());
|
||||
}
|
||||
|
||||
let data: Vec<u16> = (0..(len - 1))
|
||||
.map(|_| self.read_u16::<LittleEndian>())
|
||||
.collect::<io::Result<_>>()?;
|
||||
self.read_u16::<LittleEndian>()?;
|
||||
String::from_utf16(&data)
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-16"))
|
||||
}
|
||||
|
||||
fn expect_end(&mut self) -> io::Result<()>;
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||
fn expect_end(&mut self) -> io::Result<()> {
|
||||
let len = self.get_ref().as_ref().len();
|
||||
if len as u64 != self.position() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
format!(
|
||||
"Buffer contained {} bytes, expected {} bytes",
|
||||
len,
|
||||
self.position()
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Write: WriteBytesExt {
|
||||
fn write_ptp_u8(&mut self, v: &u8) -> io::Result<()> {
|
||||
self.write_u8(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_i8(&mut self, v: &i8) -> io::Result<()> {
|
||||
self.write_i8(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_u16(&mut self, v: &u16) -> io::Result<()> {
|
||||
self.write_u16::<LittleEndian>(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_i16(&mut self, v: &i16) -> io::Result<()> {
|
||||
self.write_i16::<LittleEndian>(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_u32(&mut self, v: &u32) -> io::Result<()> {
|
||||
self.write_u32::<LittleEndian>(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_i32(&mut self, v: &i32) -> io::Result<()> {
|
||||
self.write_i32::<LittleEndian>(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_u64(&mut self, v: &u64) -> io::Result<()> {
|
||||
self.write_u64::<LittleEndian>(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_i64(&mut self, v: &i64) -> io::Result<()> {
|
||||
self.write_i64::<LittleEndian>(*v)
|
||||
}
|
||||
|
||||
fn write_ptp_vec<T, F>(&mut self, vec: &[T], func: F) -> io::Result<()>
|
||||
where
|
||||
F: Fn(&mut Self, &T) -> io::Result<()>,
|
||||
{
|
||||
self.write_u32::<LittleEndian>(vec.len() as u32)?;
|
||||
for v in vec {
|
||||
func(self, v)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_ptp_u8_vec(&mut self, vec: &[u8]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_u8(v))
|
||||
}
|
||||
|
||||
fn write_ptp_i8_vec(&mut self, vec: &[i8]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_i8(v))
|
||||
}
|
||||
|
||||
fn write_ptp_u16_vec(&mut self, vec: &[u16]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_u16(v))
|
||||
}
|
||||
|
||||
fn write_ptp_i16_vec(&mut self, vec: &[i16]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_i16(v))
|
||||
}
|
||||
|
||||
fn write_ptp_u32_vec(&mut self, vec: &[u32]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_u32(v))
|
||||
}
|
||||
|
||||
fn write_ptp_i32_vec(&mut self, vec: &[i32]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_i32(v))
|
||||
}
|
||||
|
||||
fn write_ptp_u64_vec(&mut self, vec: &[u64]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_u64(v))
|
||||
}
|
||||
|
||||
fn write_ptp_i64_vec(&mut self, vec: &[i64]) -> io::Result<()> {
|
||||
self.write_ptp_vec(vec, |cur, v| cur.write_ptp_i64(v))
|
||||
}
|
||||
|
||||
fn write_ptp_str(&mut self, s: &str) -> io::Result<()> {
|
||||
if s.is_empty() {
|
||||
return self.write_u8(0);
|
||||
}
|
||||
|
||||
let utf16: Vec<u16> = s.encode_utf16().collect();
|
||||
self.write_u8((utf16.len() + 1) as u8)?;
|
||||
for c in utf16 {
|
||||
self.write_u16::<LittleEndian>(c)?;
|
||||
}
|
||||
self.write_u16::<LittleEndian>(0)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Vec<u8> {}
|
||||
|
||||
pub trait PtpSerialize: Sized {
|
||||
fn try_into_ptp(&self) -> io::Result<Vec<u8>>;
|
||||
|
||||
fn try_write_ptp(&self, buf: &mut Vec<u8>) -> io::Result<()>;
|
||||
}
|
||||
|
||||
pub trait PtpDeserialize: Sized {
|
||||
fn try_from_ptp(buf: &[u8]) -> io::Result<Self>;
|
||||
|
||||
fn try_read_ptp<R: Read>(cur: &mut R) -> io::Result<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_ptp {
|
||||
($ty:ty, $read_fn:ident, $write_fn:ident) => {
|
||||
impl PtpSerialize for $ty {
|
||||
fn try_into_ptp(&self) -> io::Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
self.try_write_ptp(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn try_write_ptp(&self, buf: &mut Vec<u8>) -> io::Result<()> {
|
||||
buf.$write_fn(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PtpDeserialize for $ty {
|
||||
fn try_from_ptp(buf: &[u8]) -> io::Result<Self> {
|
||||
let mut cur = Cursor::new(buf);
|
||||
let val = Self::try_read_ptp(&mut cur)?;
|
||||
cur.expect_end()?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn try_read_ptp<R: Read>(cur: &mut R) -> io::Result<Self> {
|
||||
cur.$read_fn()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_ptp!(u8, read_ptp_u8, write_ptp_u8);
|
||||
impl_ptp!(i8, read_ptp_i8, write_ptp_i8);
|
||||
impl_ptp!(u16, read_ptp_u16, write_ptp_u16);
|
||||
impl_ptp!(i16, read_ptp_i16, write_ptp_i16);
|
||||
impl_ptp!(u32, read_ptp_u32, write_ptp_u32);
|
||||
impl_ptp!(i32, read_ptp_i32, write_ptp_i32);
|
||||
impl_ptp!(u64, read_ptp_u64, write_ptp_u64);
|
||||
impl_ptp!(i64, read_ptp_i64, write_ptp_i64);
|
||||
impl_ptp!(String, read_ptp_str, write_ptp_str);
|
||||
impl_ptp!(Vec<u8>, read_ptp_u8_vec, write_ptp_u8_vec);
|
||||
impl_ptp!(Vec<i8>, read_ptp_i8_vec, write_ptp_i8_vec);
|
||||
impl_ptp!(Vec<u16>, read_ptp_u16_vec, write_ptp_u16_vec);
|
||||
impl_ptp!(Vec<i16>, read_ptp_i16_vec, write_ptp_i16_vec);
|
||||
impl_ptp!(Vec<u32>, read_ptp_u32_vec, write_ptp_u32_vec);
|
||||
impl_ptp!(Vec<i32>, read_ptp_i32_vec, write_ptp_i32_vec);
|
||||
impl_ptp!(Vec<u64>, read_ptp_u64_vec, write_ptp_u64_vec);
|
||||
impl_ptp!(Vec<i64>, read_ptp_i64_vec, write_ptp_i64_vec);
|
62
crates/ptp/macro/Cargo.lock
generated
Normal file
62
crates/ptp/macro/Cargo.lock
generated
Normal file
@@ -0,0 +1,62 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptp_cursor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptp_macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"proc-macro2",
|
||||
"ptp_cursor",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
14
crates/ptp/macro/Cargo.toml
Normal file
14
crates/ptp/macro/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "ptp_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.5.0"
|
||||
proc-macro2 = "1.0.101"
|
||||
quote = "1.0.41"
|
||||
syn = { version = "2.0.106", features = ["full"] }
|
||||
ptp_cursor = { path = "../cursor" }
|
253
crates/ptp/macro/src/lib.rs
Normal file
253
crates/ptp/macro/src/lib.rs
Normal file
@@ -0,0 +1,253 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{Data, DeriveInput, Expr, Fields, parse_macro_input, punctuated::Punctuated};
|
||||
|
||||
#[proc_macro_derive(PtpSerialize)]
|
||||
pub fn derive_ptp_serialize(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = &input.ident;
|
||||
|
||||
let expanded = match &input.data {
|
||||
Data::Struct(s) => match &s.fields {
|
||||
Fields::Named(named) => {
|
||||
let fields = &named.named;
|
||||
|
||||
let write_fields = fields.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
quote! {
|
||||
self.#name.try_write_ptp(buf)?;
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
impl ptp_cursor::PtpSerialize for #name {
|
||||
fn try_into_ptp(&self) -> std::io::Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
self.try_write_ptp(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn try_write_ptp(&self, buf: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
#(#write_fields)*
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fields::Unnamed(unnamed) => {
|
||||
let fields = &unnamed.unnamed;
|
||||
|
||||
let write_fields = (0..fields.len()).map(|i| {
|
||||
let idx = syn::Index::from(i);
|
||||
quote! { self.#idx.try_write_ptp(buf)?; }
|
||||
});
|
||||
|
||||
quote! {
|
||||
impl ptp_cursor::PtpSerialize for #name {
|
||||
fn try_into_ptp(&self) -> std::io::Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
self.try_write_ptp(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn try_write_ptp(&self, buf: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
#(#write_fields)*
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fields::Unit => {
|
||||
quote! {
|
||||
impl ptp_cursor::PtpSerialize for #name {
|
||||
fn try_into_ptp(&self) -> std::io::Result<Vec<u8>> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
fn try_write_ptp(&self, _buf: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Data::Enum(_) => {
|
||||
let repr_ty = input
|
||||
.attrs
|
||||
.iter()
|
||||
.find_map(|attr| {
|
||||
if attr.path().is_ident("repr") {
|
||||
attr.parse_args_with(
|
||||
Punctuated::<Expr, syn::Token![,]>::parse_separated_nonempty,
|
||||
)
|
||||
.ok()
|
||||
.and_then(|args| args.into_iter().next())
|
||||
.and_then(|expr| match expr {
|
||||
Expr::Path(path) => path.path.get_ident().cloned(),
|
||||
_ => None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.expect("Enums must have a #[repr(T)] attribute for PtpSerialize");
|
||||
|
||||
quote! {
|
||||
impl ptp_cursor::PtpSerialize for #name
|
||||
where
|
||||
#name: Clone + Copy + TryFrom<#repr_ty> + Into<#repr_ty>
|
||||
{
|
||||
fn try_into_ptp(&self) -> std::io::Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
self.try_write_ptp(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn try_write_ptp(&self, buf: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
let discriminant: #repr_ty = (*self).into();
|
||||
discriminant.try_write_ptp(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("PtpSerialize cannot be automatically derived for unions")
|
||||
}
|
||||
};
|
||||
|
||||
expanded.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(PtpDeserialize)]
|
||||
pub fn derive_ptp_deserialize(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = &input.ident;
|
||||
|
||||
let expanded = match &input.data {
|
||||
Data::Struct(s) => match &s.fields {
|
||||
Fields::Named(named) => {
|
||||
let fields = &named.named;
|
||||
|
||||
let read_fields = fields.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
let ty = &f.ty;
|
||||
quote! {
|
||||
#name: <#ty>::try_read_ptp(cur)?
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
impl ptp_cursor::PtpDeserialize for #name {
|
||||
fn try_from_ptp(buf: &[u8]) -> std::io::Result<Self> {
|
||||
use ptp_cursor::Read;
|
||||
|
||||
let mut cur = std::io::Cursor::new(buf);
|
||||
let val = Self::try_read_ptp(&mut cur)?;
|
||||
cur.expect_end()?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn try_read_ptp<R: ptp_cursor::Read>(cur: &mut R) -> std::io::Result<Self> {
|
||||
Ok(Self { #(#read_fields),* })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fields::Unnamed(unnamed) => {
|
||||
let fields = &unnamed.unnamed;
|
||||
|
||||
let read_fields = fields.iter().map(|f| {
|
||||
let ty = &f.ty;
|
||||
quote! { <#ty>::try_read_ptp(cur)? }
|
||||
});
|
||||
|
||||
quote! {
|
||||
impl ptp_cursor::PtpDeserialize for #name {
|
||||
fn try_from_ptp(buf: &[u8]) -> std::io::Result<Self> {
|
||||
use ptp_cursor::Read;
|
||||
|
||||
let mut cur = std::io::Cursor::new(buf);
|
||||
let val = Self::try_read_ptp(&mut cur)?;
|
||||
cur.expect_end()?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn try_read_ptp<R: ptp_cursor::Read>(cur: &mut R) -> std::io::Result<Self> {
|
||||
Ok(Self(#(#read_fields),*))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fields::Unit => {
|
||||
quote! {
|
||||
impl ptp_cursor::PtpDeserialize for #name {
|
||||
fn try_from_ptp(buf: &[u8]) -> std::io::Result<Self> {
|
||||
use ptp_cursor::Read;
|
||||
|
||||
let mut cur = std::io::Cursor::new(buf);
|
||||
cur.expect_end()?;
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
fn try_read_ptp<R: ptp_cursor::Read>(_cur: &mut R) -> std::io::Result<Self> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Data::Enum(_) => {
|
||||
let repr_ty = input
|
||||
.attrs
|
||||
.iter()
|
||||
.find_map(|attr| {
|
||||
if attr.path().is_ident("repr") {
|
||||
attr.parse_args_with(
|
||||
Punctuated::<Expr, syn::Token![,]>::parse_separated_nonempty,
|
||||
)
|
||||
.ok()
|
||||
.and_then(|args| args.into_iter().next())
|
||||
.and_then(|expr| match expr {
|
||||
Expr::Path(path) => path.path.get_ident().cloned(),
|
||||
_ => None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.expect("Enums must have a #[repr(T)] attribute for PtpDeserialize");
|
||||
|
||||
quote! {
|
||||
impl ptp_cursor::PtpDeserialize for #name
|
||||
where
|
||||
#name: Clone + Copy + TryFrom<#repr_ty> + Into<#repr_ty>
|
||||
{
|
||||
fn try_from_ptp(buf: &[u8]) -> std::io::Result<Self> {
|
||||
use ptp_cursor::Read;
|
||||
|
||||
let mut cur = std::io::Cursor::new(buf);
|
||||
let val = Self::try_read_ptp(&mut cur)?;
|
||||
cur.expect_end()?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn try_read_ptp<R: ptp_cursor::Read>(cur: &mut R) -> std::io::Result<Self> {
|
||||
let discriminant = <#repr_ty>::try_read_ptp(cur)?;
|
||||
discriminant.try_into().map_err(|_| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
format!("Invalid discriminant for {}: {:?}", stringify!(#name), discriminant)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("PtpDeserialize cannot be automatically derived for unions")
|
||||
}
|
||||
};
|
||||
|
||||
expanded.into()
|
||||
}
|
Reference in New Issue
Block a user