#![forbid(future_incompatible)]
#![doc = include_str!("../README.md")]
pub mod ids;
pub mod l2cap;
pub mod types;
use types::{ActionRc, ListRc, OpType};
pub type Result<T> = core::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Invalid UTF8 string: {0}")]
BadUtf8(#[from] core::str::Utf8Error),
#[error("Invalid UUID: {0}")]
BadUuid(#[from] uuid::Error),
#[error("Not supported")]
NotSupported,
#[error("Not found")]
NotFound,
#[error("No response")]
NoResponse,
#[error("Invalid response")]
BadResponse,
#[error("Invalid UUID size: {0}")]
BadUuidSize(usize),
#[error("Object list error: {0:?}")]
ListError(#[from] ListRc),
#[error("Object action error: {0:?}")]
ActionError(#[from] ActionRc),
#[error("Invalid action features: {0:08x?}")]
BadActionFeatures(u32),
#[error("Invalid list features: {0:08x?}")]
BadListFeatures(u32),
#[error("Invalid properties: {0:08x?}")]
BadProperties(u32),
#[error("Invalid directory flags: {0:02x?}")]
BadDirFlags(u8),
#[error("Not enough data ({actual} < {needed})")]
NotEnoughData {
actual: usize,
needed: usize,
},
#[error("Too many data ({actual} > {needed})")]
TooManyData {
actual: usize,
needed: usize,
},
#[error("Invalid opcode for {type_}: {code:02x?}")]
BadOpCode {
type_: OpType,
code: u8,
},
}
impl From<std::string::FromUtf8Error> for Error {
fn from(err: std::string::FromUtf8Error) -> Self {
Self::BadUtf8(err.utf8_error())
}
}
impl Error {
pub fn check_len(actual: usize, needed: usize) -> Result<()> {
if actual < needed {
Err(Error::NotEnoughData { actual, needed })
} else {
Ok(())
}
}
pub fn check_size<T: Sized>(actual: usize) -> Result<()> {
Self::check_len(actual, core::mem::size_of::<T>())
}
pub fn check_len_exact(actual: usize, needed: usize) -> Result<()> {
Self::check_len(actual, needed)?;
if actual > needed {
Err(Error::TooManyData { actual, needed })
} else {
Ok(())
}
}
pub fn check_size_exact<T: Sized>(actual: usize) -> Result<()> {
Self::check_len_exact(actual, core::mem::size_of::<T>())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct Sizes {
pub current: usize,
pub allocated: usize,
}
impl From<&[u8; 8]> for Sizes {
fn from(raw: &[u8; 8]) -> Self {
let sizes = types::Sizes::from(raw);
Self {
current: sizes.current as _,
allocated: sizes.allocated as _,
}
}
}
impl TryFrom<&[u8]> for Sizes {
type Error = Error;
fn try_from(raw: &[u8]) -> Result<Self> {
Error::check_size_exact::<types::Sizes>(raw.len())?;
let sizes = types::Sizes::try_from(raw)?;
Ok(Self {
current: sizes.current as _,
allocated: sizes.allocated as _,
})
}
}