ots_core/
lib.rs

1#![forbid(future_incompatible)]
2//#![deny(bad_style, missing_docs)]
3#![doc = include_str!("../README.md")]
4
5pub mod ids;
6pub mod l2cap;
7pub mod types;
8
9use types::{ActionRc, ListRc, OpType};
10
11/// OTS client result
12pub type Result<T> = core::result::Result<T, Error>;
13
14/// OTS client error
15#[derive(thiserror::Error, Debug)]
16pub enum Error {
17    /// UTF-8 decoding error
18    #[error("Invalid UTF8 string: {0}")]
19    BadUtf8(#[from] core::str::Utf8Error),
20    /// UUID decoding error
21    #[error("Invalid UUID: {0}")]
22    BadUuid(#[from] uuid::Error),
23    /// Not supported function requested
24    #[error("Not supported")]
25    NotSupported,
26    /// Object not found
27    #[error("Not found")]
28    NotFound,
29    /// No response received
30    #[error("No response")]
31    NoResponse,
32    /// Invalid response received
33    #[error("Invalid response")]
34    BadResponse,
35    /// Invalid UUID size
36    #[error("Invalid UUID size: {0}")]
37    BadUuidSize(usize),
38    /// Object list operation failed
39    #[error("Object list error: {0:?}")]
40    ListError(#[from] ListRc),
41    /// Object action operation failed
42    #[error("Object action error: {0:?}")]
43    ActionError(#[from] ActionRc),
44    /// Invalid action features received
45    #[error("Invalid action features: {0:08x?}")]
46    BadActionFeatures(u32),
47    /// Invalid list features received
48    #[error("Invalid list features: {0:08x?}")]
49    BadListFeatures(u32),
50    /// Invalid properties received
51    #[error("Invalid properties: {0:08x?}")]
52    BadProperties(u32),
53    /// Invalid directory flags received
54    #[error("Invalid directory flags: {0:02x?}")]
55    BadDirFlags(u8),
56    /// Not enough data to parse
57    #[error("Not enough data ({actual} < {needed})")]
58    NotEnoughData {
59        /// Actual size
60        actual: usize,
61        /// Expected size
62        needed: usize,
63    },
64    /// Too many data to parse
65    #[error("Too many data ({actual} > {needed})")]
66    TooManyData {
67        /// Actual size
68        actual: usize,
69        /// Expected size
70        needed: usize,
71    },
72    /// Invalid operation code received
73    #[error("Invalid opcode for {type_}: {code:02x?}")]
74    BadOpCode {
75        /// Operation type
76        type_: OpType,
77        /// Operation code
78        code: u8,
79    },
80}
81
82impl From<std::string::FromUtf8Error> for Error {
83    fn from(err: std::string::FromUtf8Error) -> Self {
84        Self::BadUtf8(err.utf8_error())
85    }
86}
87
88impl Error {
89    /// Check that data length is greater or equals needed
90    pub fn check_len(actual: usize, needed: usize) -> Result<()> {
91        if actual < needed {
92            Err(Error::NotEnoughData { actual, needed })
93        } else {
94            Ok(())
95        }
96    }
97
98    /// Check that data length is greater or equals needed
99    pub fn check_size<T: Sized>(actual: usize) -> Result<()> {
100        Self::check_len(actual, core::mem::size_of::<T>())
101    }
102
103    /// Check that data length is exact needed
104    pub fn check_len_exact(actual: usize, needed: usize) -> Result<()> {
105        Self::check_len(actual, needed)?;
106        if actual > needed {
107            Err(Error::TooManyData { actual, needed })
108        } else {
109            Ok(())
110        }
111    }
112
113    /// Check that data length is exact needed
114    pub fn check_size_exact<T: Sized>(actual: usize) -> Result<()> {
115        Self::check_len_exact(actual, core::mem::size_of::<T>())
116    }
117}
118
119/// Object sizes (current and allocated)
120#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
121#[repr(C)]
122pub struct Sizes {
123    /// Current size of object
124    pub current: usize,
125    /// Allocated size of object
126    pub allocated: usize,
127}
128
129impl From<&[u8; 8]> for Sizes {
130    fn from(raw: &[u8; 8]) -> Self {
131        let sizes = types::Sizes::from(raw);
132        Self {
133            current: sizes.current as _,
134            allocated: sizes.allocated as _,
135        }
136    }
137}
138
139impl TryFrom<&[u8]> for Sizes {
140    type Error = Error;
141
142    fn try_from(raw: &[u8]) -> Result<Self> {
143        Error::check_size_exact::<types::Sizes>(raw.len())?;
144        let sizes = types::Sizes::try_from(raw)?;
145        Ok(Self {
146            current: sizes.current as _,
147            allocated: sizes.allocated as _,
148        })
149    }
150}