1 use crate::protocol::common::hex::decode_hex; 2 use core::convert::TryFrom; 3 use core::convert::TryInto; 4 use core::num::NonZeroUsize; 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 129 /// Like [`ThreadId`], without the `Any`, or `All` variants. 130 #[derive(Debug, Copy, Clone)] 131 pub struct ConcreteThreadId { 132 /// Process ID (may or may not be present). 133 pub pid: Option<NonZeroUsize>, 134 /// Thread ID. 135 pub tid: NonZeroUsize, 136 } 137 138 impl TryFrom<ThreadId> for ConcreteThreadId { 139 type Error = (); 140 try_from(thread: ThreadId) -> Result<ConcreteThreadId, ()>141 fn try_from(thread: ThreadId) -> Result<ConcreteThreadId, ()> { 142 Ok(ConcreteThreadId { 143 pid: match thread.pid { 144 None => None, 145 Some(id_kind) => Some(id_kind.try_into()?), 146 }, 147 tid: thread.tid.try_into()?, 148 }) 149 } 150 } 151 152 impl TryFrom<IdKind> for NonZeroUsize { 153 type Error = (); 154 try_from(value: IdKind) -> Result<NonZeroUsize, ()>155 fn try_from(value: IdKind) -> Result<NonZeroUsize, ()> { 156 match value { 157 IdKind::WithId(v) => Ok(v), 158 _ => Err(()), 159 } 160 } 161 } 162