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