use crate::protocol::common::hex::decode_hex; use core::convert::TryFrom; use core::convert::TryInto; use core::num::NonZeroUsize; /// Tid/Pid Selector. #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum IdKind { /// All threads (-1) All, /// Any thread (0) Any, /// Thread with specific ID (id > 0) WithId(NonZeroUsize), } /// Unique Thread ID. #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub struct ThreadId { /// Process ID (may or may not be present). pub pid: Option, /// Thread ID. pub tid: IdKind, } impl TryFrom<&[u8]> for ThreadId { type Error = (); fn try_from(s: &[u8]) -> Result { match s { [b'p', s @ ..] => { // p. let mut s = s.split(|b| *b == b'.'); let pid: IdKind = s.next().ok_or(())?.try_into()?; let tid: IdKind = match s.next() { Some(s) => s.try_into()?, None => IdKind::All, // sending only p is valid }; Ok(ThreadId { pid: Some(pid), tid, }) } _ => { // let tid: IdKind = s.try_into()?; Ok(ThreadId { pid: None, tid }) } } } } impl TryFrom<&[u8]> for IdKind { type Error = (); fn try_from(s: &[u8]) -> Result { Ok(match s { b"-1" => IdKind::All, b"0" => IdKind::Any, id => IdKind::WithId(NonZeroUsize::new(decode_hex(id).map_err(drop)?).ok_or(())?), }) } } impl TryFrom<&mut [u8]> for ThreadId { type Error = (); fn try_from(s: &mut [u8]) -> Result { Self::try_from(s as &[u8]) } } impl TryFrom<&mut [u8]> for IdKind { type Error = (); fn try_from(s: &mut [u8]) -> Result { Self::try_from(s as &[u8]) } } /// Like [`IdKind`], without the `Any` variant. Typically used when working /// with vCont (i.e: where the `Any` variant wouldn't be valid). #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum SpecificIdKind { /// Thread with specific ID (id > 0) WithId(core::num::NonZeroUsize), /// All threads (-1) All, } /// Like [`ThreadId`], without the `Any` variants. Typically used when working /// with vCont (i.e: where the `Any` variant wouldn't be valid). #[derive(Debug, Copy, Clone)] pub struct SpecificThreadId { /// Process ID (may or may not be present). pub pid: Option, /// Thread ID. pub tid: SpecificIdKind, } impl TryFrom for SpecificIdKind { type Error = (); fn try_from(id: IdKind) -> Result { Ok(match id { IdKind::All => SpecificIdKind::All, IdKind::WithId(id) => SpecificIdKind::WithId(id), IdKind::Any => return Err(()), }) } } impl TryFrom for SpecificThreadId { type Error = (); fn try_from(thread: ThreadId) -> Result { Ok(SpecificThreadId { pid: match thread.pid { None => None, Some(id_kind) => Some(id_kind.try_into()?), }, tid: thread.tid.try_into()?, }) } } /// Like [`ThreadId`], without the `Any`, or `All` variants. #[derive(Debug, Copy, Clone)] pub struct ConcreteThreadId { /// Process ID (may or may not be present). pub pid: Option, /// Thread ID. pub tid: NonZeroUsize, } impl TryFrom for ConcreteThreadId { type Error = (); fn try_from(thread: ThreadId) -> Result { Ok(ConcreteThreadId { pid: match thread.pid { None => None, Some(id_kind) => Some(id_kind.try_into()?), }, tid: thread.tid.try_into()?, }) } } impl TryFrom for NonZeroUsize { type Error = (); fn try_from(value: IdKind) -> Result { match value { IdKind::WithId(v) => Ok(v), _ => Err(()), } } }