1 use core::convert::{TryFrom, TryInto}; 2 use core::num::NonZeroUsize; 3 4 use super::hex::decode_hex; 5 6 /// Tid/Pid Selector. 7 #[derive(PartialEq, Eq, Debug, Clone, Copy)] 8 pub enum IdKind { 9 /// All threads (-1) 10 All, 11 /// Any thread (0) 12 Any, 13 /// Thread with specific ID (id > 0) 14 WithId(NonZeroUsize), 15 } 16 17 /// Unique Thread ID. 18 #[derive(PartialEq, Eq, Debug, Clone, Copy)] 19 pub struct ThreadId { 20 /// Process ID (may or may not be present). 21 pub pid: Option<IdKind>, 22 /// Thread ID. 23 pub tid: IdKind, 24 } 25 26 impl TryFrom<&[u8]> for ThreadId { 27 type Error = (); 28 try_from(s: &[u8]) -> Result<Self, ()>29 fn try_from(s: &[u8]) -> Result<Self, ()> { 30 match s { 31 [b'p', s @ ..] => { 32 // p<pid>.<tid> 33 let mut s = s.split(|b| *b == b'.'); 34 let pid: IdKind = s.next().ok_or(())?.try_into()?; 35 let tid: IdKind = match s.next() { 36 Some(s) => s.try_into()?, 37 None => IdKind::All, // sending only p<pid> is valid 38 }; 39 40 Ok(ThreadId { 41 pid: Some(pid), 42 tid, 43 }) 44 } 45 _ => { 46 // <tid> 47 let tid: IdKind = s.try_into()?; 48 49 Ok(ThreadId { pid: None, tid }) 50 } 51 } 52 } 53 } 54 55 impl TryFrom<&[u8]> for IdKind { 56 type Error = (); 57 try_from(s: &[u8]) -> Result<Self, ()>58 fn try_from(s: &[u8]) -> Result<Self, ()> { 59 Ok(match s { 60 b"-1" => IdKind::All, 61 b"0" => IdKind::Any, 62 id => IdKind::WithId(NonZeroUsize::new(decode_hex(id).map_err(drop)?).ok_or(())?), 63 }) 64 } 65 } 66 67 impl TryFrom<&mut [u8]> for ThreadId { 68 type Error = (); 69 try_from(s: &mut [u8]) -> Result<Self, ()>70 fn try_from(s: &mut [u8]) -> Result<Self, ()> { 71 Self::try_from(s as &[u8]) 72 } 73 } 74 75 impl TryFrom<&mut [u8]> for IdKind { 76 type Error = (); 77 try_from(s: &mut [u8]) -> Result<Self, ()>78 fn try_from(s: &mut [u8]) -> Result<Self, ()> { 79 Self::try_from(s as &[u8]) 80 } 81 } 82 83 /// Like [`IdKind`], without the `Any` variant. Typically used when working 84 /// with vCont (i.e: where the `Any` variant wouldn't be valid). 85 #[derive(PartialEq, Eq, Debug, Clone, Copy)] 86 pub enum SpecificIdKind { 87 /// Thread with specific ID (id > 0) 88 WithId(core::num::NonZeroUsize), 89 /// All threads (-1) 90 All, 91 } 92 93 /// Like [`ThreadId`], without the `Any` variants. Typically used when working 94 /// with vCont (i.e: where the `Any` variant wouldn't be valid). 95 #[derive(Debug, Copy, Clone)] 96 pub struct SpecificThreadId { 97 /// Process ID (may or may not be present). 98 pub pid: Option<SpecificIdKind>, 99 /// Thread ID. 100 pub tid: SpecificIdKind, 101 } 102 103 impl TryFrom<IdKind> for SpecificIdKind { 104 type Error = (); 105 try_from(id: IdKind) -> Result<SpecificIdKind, ()>106 fn try_from(id: IdKind) -> Result<SpecificIdKind, ()> { 107 Ok(match id { 108 IdKind::All => SpecificIdKind::All, 109 IdKind::WithId(id) => SpecificIdKind::WithId(id), 110 IdKind::Any => return Err(()), 111 }) 112 } 113 } 114 115 impl TryFrom<ThreadId> for SpecificThreadId { 116 type Error = (); 117 try_from(thread: ThreadId) -> Result<SpecificThreadId, ()>118 fn try_from(thread: ThreadId) -> Result<SpecificThreadId, ()> { 119 Ok(SpecificThreadId { 120 pid: match thread.pid { 121 None => None, 122 Some(id_kind) => Some(id_kind.try_into()?), 123 }, 124 tid: thread.tid.try_into()?, 125 }) 126 } 127 } 128