valence_command/
parsers.rs

1//! A collection of parses for use in command argument nodes.
2pub mod angle;
3pub mod block_pos;
4pub mod bool;
5pub mod color;
6pub mod column_pos;
7pub mod entity_anchor;
8pub mod entity_selector;
9pub mod gamemode;
10pub mod inventory_slot;
11pub mod numbers;
12pub mod rotation;
13pub mod score_holder;
14pub mod strings;
15pub mod swizzle;
16pub mod time;
17pub mod vec2;
18pub mod vec3;
19
20use std::ops::Add;
21
22pub use block_pos::BlockPos;
23pub use column_pos::ColumnPos;
24pub use entity_anchor::EntityAnchor;
25pub use entity_selector::EntitySelector;
26pub use inventory_slot::InventorySlot;
27pub use rotation::Rotation;
28pub use score_holder::ScoreHolder;
29pub use strings::{GreedyString, QuotableString};
30pub use swizzle::Swizzle;
31use thiserror::Error;
32pub use time::Time;
33use tracing::error;
34pub(crate) use valence_server::protocol::packets::play::command_tree_s2c::Parser;
35pub use vec2::Vec2;
36pub use vec3::Vec3;
37
38pub trait CommandArg: Sized {
39    fn arg_from_str(string: &str) -> Result<Self, CommandArgParseError> {
40        Self::parse_arg(&mut ParseInput::new(string))
41    }
42
43    fn parse_arg(input: &mut ParseInput) -> Result<Self, CommandArgParseError>;
44    /// what will the client be sent
45    fn display() -> Parser;
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct ParseInput<'a>(&'a str);
50
51impl<'a> ParseInput<'a> {
52    fn advance(&mut self) {
53        self.advance_n_chars(1);
54    }
55
56    fn advance_n_chars(&mut self, n: usize) {
57        if self.is_done() {
58            return;
59        }
60        match self.0.char_indices().nth(n) {
61            Some((len, _)) => {
62                self.0 = &self.0[len..];
63            }
64            None => {
65                self.0 = &self.0[self.0.len()..];
66            }
67        }
68    }
69
70    fn advance_n_bytes(&mut self, n: usize) {
71        if self.is_done() {
72            return;
73        }
74        self.0 = &self.0[n..];
75    }
76    pub fn new(input: &'a str) -> Self {
77        ParseInput(input)
78    }
79
80    /// Returns the next character without advancing the input
81    pub fn peek(&self) -> Option<char> {
82        self.0.chars().next()
83    }
84
85    /// Returns the next n characters without advancing the input
86    pub fn peek_n(&self, n: usize) -> &'a str {
87        self.0
88            .char_indices()
89            .nth(n)
90            .map_or(self.0, |(idx, _)| &self.0[..idx])
91    }
92
93    /// Returns the next word without advancing the input
94    pub fn peek_word(&self) -> &'a str {
95        self.0
96            .char_indices()
97            .find(|(_, c)| c.is_whitespace())
98            .map_or(self.0, |(idx, _)| &self.0[..idx])
99    }
100
101    /// Checks if the input is empty
102    pub fn is_done(&self) -> bool {
103        self.0.is_empty()
104    }
105
106    /// Returns the next character and advances the input
107    pub fn pop(&mut self) -> Option<char> {
108        let c = self.peek()?;
109        self.advance();
110        Some(c)
111    }
112
113    /// Returns the next n characters and advances the input
114    pub fn pop_n(&mut self, n: usize) -> &str {
115        let s = self.peek_n(n);
116        self.advance_n_bytes(s.len());
117        s
118    }
119
120    /// Returns the next word and advances the input
121    pub fn pop_word(&mut self) -> &str {
122        let s = self.peek_word();
123        self.advance_n_bytes(s.len());
124        s
125    }
126
127    /// Returns the rest of the input and advances the input
128    pub fn pop_all(&mut self) -> Option<&str> {
129        let s = self.0;
130        self.advance_n_bytes(self.0.len());
131        Some(s)
132    }
133
134    /// Returns the next word and advances the input
135    pub fn pop_to_next(&mut self, c: char) -> Option<&str> {
136        let pos = self.0.find(c)?;
137        let s = &self.0[..pos];
138        self.advance_n_bytes(pos);
139        Some(s)
140    }
141
142    /// Matches the case-insensitive string and advances the input if it matches
143    pub fn match_next(&mut self, string: &str) -> bool {
144        if self
145            .0
146            .to_lowercase()
147            .starts_with(string.to_lowercase().as_str())
148        {
149            self.advance_n_bytes(string.len());
150            true
151        } else {
152            false
153        }
154    }
155
156    /// Skip all whitespace at the front of the input
157    pub fn skip_whitespace(&mut self) {
158        while let Some(c) = self.peek() {
159            if c.is_whitespace() {
160                self.advance();
161            } else {
162                break;
163            }
164        }
165    }
166
167    /// Set the inner string
168    pub fn into_inner(self) -> &'a str {
169        self.0
170    }
171
172    #[allow(clippy::len_without_is_empty)]
173    pub fn len(&self) -> usize {
174        self.0.len()
175    }
176}
177
178#[derive(Debug, Error)]
179pub enum CommandArgParseError {
180    // these should be player facing and not disclose internal information
181    #[error("invalid argument, expected {expected} got {got}")] // e.g. "integer" number
182    InvalidArgument { expected: String, got: String },
183    #[error("invalid argument length")]
184    InvalidArgLength,
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
188pub enum AbsoluteOrRelative<T> {
189    Absolute(T),
190    Relative(T), // current value + T
191}
192
193impl<T> AbsoluteOrRelative<T>
194where
195    T: Add<Output = T> + Copy,
196{
197    pub fn get(&self, original: T) -> T {
198        match self {
199            Self::Absolute(num) => *num,
200            Self::Relative(num) => *num + original,
201        }
202    }
203}
204
205impl<T> CommandArg for AbsoluteOrRelative<T>
206where
207    T: CommandArg + Default,
208{
209    fn parse_arg(input: &mut ParseInput) -> Result<Self, CommandArgParseError> {
210        input.skip_whitespace();
211        if input.peek() == Some('~') {
212            input.advance();
213            if input.peek() == Some(' ') || input.peek().is_none() {
214                Ok(AbsoluteOrRelative::Relative(T::default()))
215            } else {
216                Ok(AbsoluteOrRelative::Relative(T::parse_arg(input)?))
217            }
218        } else if input.peek() == Some(' ') || input.peek().is_none() {
219            Err(CommandArgParseError::InvalidArgLength)
220        } else {
221            Ok(AbsoluteOrRelative::Absolute(T::parse_arg(input)?))
222        }
223    }
224
225    fn display() -> Parser {
226        T::display()
227    }
228}
229
230impl<T: Default> Default for AbsoluteOrRelative<T> {
231    fn default() -> Self {
232        AbsoluteOrRelative::Absolute(T::default())
233    }
234}
235
236#[cfg(test)]
237mod test {
238    use super::*;
239    #[test]
240    fn test_parse_input() {
241        let mut input = ParseInput::new("The QuIck brown FOX jumps over the lazy dog");
242        assert_eq!(input.peek(), Some('T'));
243        assert_eq!(input.peek_n(0), "");
244        assert_eq!(input.peek_n(1), "T");
245        assert_eq!(input.peek_n(2), "Th");
246        assert_eq!(input.peek_n(3), "The");
247
248        assert_eq!(input.peek_word(), "The");
249        input.pop_word();
250        input.skip_whitespace();
251        assert_eq!(input.peek_word(), "QuIck");
252
253        assert!(input.match_next("quick"));
254        input.pop();
255        assert_eq!(input.peek_word(), "brown");
256
257        assert!(input.match_next("brown fox"));
258        assert_eq!(input.pop_all(), Some(" jumps over the lazy dog"));
259    }
260    #[test]
261    fn test_absolute_or_relative() {
262        let mut input = ParseInput::new("~");
263        assert_eq!(
264            AbsoluteOrRelative::<i32>::parse_arg(&mut input).unwrap(),
265            AbsoluteOrRelative::Relative(0)
266        );
267        assert!(input.is_done());
268
269        let mut input = ParseInput::new("~1");
270        assert_eq!(
271            AbsoluteOrRelative::<i32>::parse_arg(&mut input).unwrap(),
272            AbsoluteOrRelative::Relative(1)
273        );
274        assert!(input.is_done());
275
276        let mut input = ParseInput::new("~1.5");
277        assert_eq!(
278            AbsoluteOrRelative::<f32>::parse_arg(&mut input).unwrap(),
279            AbsoluteOrRelative::Relative(1.5)
280        );
281        assert!(input.is_done());
282
283        let mut input = ParseInput::new("1");
284        assert_eq!(
285            AbsoluteOrRelative::<i32>::parse_arg(&mut input).unwrap(),
286            AbsoluteOrRelative::Absolute(1)
287        );
288        assert!(input.is_done());
289
290        let mut input = ParseInput::new("1.5 ");
291        assert_eq!(
292            AbsoluteOrRelative::<f32>::parse_arg(&mut input).unwrap(),
293            AbsoluteOrRelative::Absolute(1.5)
294        );
295        assert!(!input.is_done());
296
297        let mut input = ParseInput::new("1.5 2");
298        assert_eq!(
299            AbsoluteOrRelative::<f32>::parse_arg(&mut input).unwrap(),
300            AbsoluteOrRelative::Absolute(1.5)
301        );
302        assert!(!input.is_done());
303        assert_eq!(
304            AbsoluteOrRelative::<f32>::parse_arg(&mut input).unwrap(),
305            AbsoluteOrRelative::Absolute(2.0)
306        );
307        assert!(input.is_done());
308    }
309}