1use crate::protocol::ToolSchema;
4use crate::DCPError;
5
6pub struct SharedArgs<'a> {
8 data: &'a [u8],
10 layout: u64,
12}
13
14impl<'a> SharedArgs<'a> {
15 pub fn new(data: &'a [u8], layout: u64) -> Self {
17 Self { data, layout }
18 }
19
20 pub fn data(&self) -> &[u8] {
22 self.data
23 }
24
25 pub fn layout(&self) -> u64 {
27 self.layout
28 }
29
30 pub fn read_str_at(&self, offset: usize, len: usize) -> Result<&str, DCPError> {
32 let end = offset.checked_add(len).ok_or(DCPError::OutOfBounds)?;
33 if end > self.data.len() {
34 return Err(DCPError::OutOfBounds);
35 }
36 std::str::from_utf8(&self.data[offset..end]).map_err(|_| DCPError::ValidationFailed)
37 }
38
39 pub fn read_i32_at(&self, offset: usize) -> Result<i32, DCPError> {
41 let end = offset.checked_add(4).ok_or(DCPError::OutOfBounds)?;
42 if end > self.data.len() {
43 return Err(DCPError::OutOfBounds);
44 }
45 let bytes: [u8; 4] = self.data[offset..end]
46 .try_into()
47 .map_err(|_| DCPError::OutOfBounds)?;
48 Ok(i32::from_le_bytes(bytes))
49 }
50
51 pub fn read_i64_at(&self, offset: usize) -> Result<i64, DCPError> {
53 let end = offset.checked_add(8).ok_or(DCPError::OutOfBounds)?;
54 if end > self.data.len() {
55 return Err(DCPError::OutOfBounds);
56 }
57 let bytes: [u8; 8] = self.data[offset..end]
58 .try_into()
59 .map_err(|_| DCPError::OutOfBounds)?;
60 Ok(i64::from_le_bytes(bytes))
61 }
62
63 pub fn read_u32_at(&self, offset: usize) -> Result<u32, DCPError> {
65 let end = offset.checked_add(4).ok_or(DCPError::OutOfBounds)?;
66 if end > self.data.len() {
67 return Err(DCPError::OutOfBounds);
68 }
69 let bytes: [u8; 4] = self.data[offset..end]
70 .try_into()
71 .map_err(|_| DCPError::OutOfBounds)?;
72 Ok(u32::from_le_bytes(bytes))
73 }
74
75 pub fn read_bytes_at(&self, offset: usize, len: usize) -> Result<&[u8], DCPError> {
77 let end = offset.checked_add(len).ok_or(DCPError::OutOfBounds)?;
78 if end > self.data.len() {
79 return Err(DCPError::OutOfBounds);
80 }
81 Ok(&self.data[offset..end])
82 }
83
84 pub fn read_bool_at(&self, offset: usize) -> Result<bool, DCPError> {
86 if offset >= self.data.len() {
87 return Err(DCPError::OutOfBounds);
88 }
89 Ok(self.data[offset] != 0)
90 }
91
92 pub fn read_f64_at(&self, offset: usize) -> Result<f64, DCPError> {
94 let end = offset.checked_add(8).ok_or(DCPError::OutOfBounds)?;
95 if end > self.data.len() {
96 return Err(DCPError::OutOfBounds);
97 }
98 let bytes: [u8; 8] = self.data[offset..end]
99 .try_into()
100 .map_err(|_| DCPError::OutOfBounds)?;
101 Ok(f64::from_le_bytes(bytes))
102 }
103}
104
105#[derive(Debug, PartialEq)]
107pub enum ToolResult {
108 Success(Vec<u8>),
110 Empty,
112 Error(DCPError),
114}
115
116impl ToolResult {
117 pub fn success(data: Vec<u8>) -> Self {
119 Self::Success(data)
120 }
121
122 pub fn empty() -> Self {
124 Self::Empty
125 }
126
127 pub fn error(err: DCPError) -> Self {
129 Self::Error(err)
130 }
131
132 pub fn is_success(&self) -> bool {
134 matches!(self, Self::Success(_) | Self::Empty)
135 }
136
137 pub fn payload(&self) -> Option<&[u8]> {
139 match self {
140 Self::Success(data) => Some(data),
141 Self::Empty => Some(&[]),
142 Self::Error(_) => None,
143 }
144 }
145}
146
147pub trait ToolHandler: Send + Sync {
149 fn execute(&self, args: &SharedArgs) -> Result<ToolResult, DCPError>;
151
152 fn schema(&self) -> &ToolSchema;
154
155 fn tool_id(&self) -> u16 {
157 self.schema().id
158 }
159
160 fn tool_name(&self) -> &'static str {
162 self.schema().name
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_shared_args_read_i32() {
172 let data = [0x01, 0x02, 0x03, 0x04];
173 let args = SharedArgs::new(&data, 0);
174 assert_eq!(args.read_i32_at(0).unwrap(), 0x04030201);
175 }
176
177 #[test]
178 fn test_shared_args_read_str() {
179 let data = b"hello world";
180 let args = SharedArgs::new(data, 0);
181 assert_eq!(args.read_str_at(0, 5).unwrap(), "hello");
182 assert_eq!(args.read_str_at(6, 5).unwrap(), "world");
183 }
184
185 #[test]
186 fn test_shared_args_bounds_check() {
187 let data = [0x01, 0x02];
188 let args = SharedArgs::new(&data, 0);
189 assert_eq!(args.read_i32_at(0), Err(DCPError::OutOfBounds));
190 assert_eq!(args.read_bytes_at(0, 10), Err(DCPError::OutOfBounds));
191 }
192
193 #[test]
194 fn test_tool_result() {
195 let success = ToolResult::success(vec![1, 2, 3]);
196 assert!(success.is_success());
197 assert_eq!(success.payload(), Some(&[1, 2, 3][..]));
198
199 let empty = ToolResult::empty();
200 assert!(empty.is_success());
201 assert_eq!(empty.payload(), Some(&[][..]));
202
203 let error = ToolResult::error(DCPError::ToolNotFound);
204 assert!(!error.is_success());
205 assert_eq!(error.payload(), None);
206 }
207}