graphite_command/
types.rs1use std::{alloc::Layout, result};
2
3use bytemuck::NoUninit;
4use bytes::BufMut;
5
6#[derive(Debug, Clone, Copy)]
7pub struct Span {
8 pub start: usize,
9 pub end: usize,
10}
11
12#[derive(Debug, Clone, Copy)]
13pub struct SpannedWord<'a> {
14 pub span: Span,
15 pub word: &'a str,
16}
17
18pub struct ParseState<'a> {
19 finalized: bool,
20 argument_layout: Layout,
21 arguments: Vec<u8>,
22 argument_spans: Vec<Span>,
23 pub(crate) words: Vec<SpannedWord<'a>>,
24 pub(crate) cursor: usize,
25 pub full_span: Span,
26}
27
28impl<'a> ParseState<'a> {
29 pub fn new(input: &'a str) -> Self {
30 let mut words = Vec::new();
31 let mut start = 0;
32 let mut end = 0;
33 let mut in_word = false;
34 for (index, char) in input.chars().enumerate() {
35 if char.is_whitespace() {
36 if in_word {
37 words.push(SpannedWord {
38 span: Span { start, end },
39 word: &input[start..=end],
40 })
41 }
42 in_word = false;
43 } else {
44 if !in_word {
45 in_word = true;
46 start = index;
47 }
48 end = index;
49 }
50 }
51 if in_word {
52 words.push(SpannedWord {
53 span: Span { start, end },
54 word: &input[start..=end],
55 })
56 }
57
58 Self {
59 finalized: false,
60 argument_layout: unsafe { Layout::from_size_align_unchecked(0, 1) },
61 arguments: Vec::new(),
62 argument_spans: Vec::new(),
63 words,
64 cursor: 0,
65 full_span: Span { start: 0, end },
66 }
67 }
68
69 pub(crate) fn get_arguments(&mut self) -> (&[u8], &[Span]) {
70 debug_assert!(!self.finalized);
71 self.finalized = true;
72
73 let len = self.argument_layout.size();
75 let align = self.argument_layout.align();
76 debug_assert_eq!(
77 len,
78 self.arguments.len(),
79 "layout length must match data length"
80 );
81
82 let padding = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
84 let padding = padding.wrapping_sub(len);
85
86 self.arguments.resize(len + padding, 0);
88
89 (self.arguments.as_slice(), self.argument_spans.as_slice())
90 }
91
92 pub(crate) fn cursor(&self) -> usize {
93 self.cursor
94 }
95
96 #[allow(dead_code)] pub(crate) fn peek_input<'b>(&'b self) -> Option<SpannedWord<'a>> {
98 if self.is_finished() {
99 None
100 } else {
101 Some(self.words[self.cursor])
102 }
103 }
104
105 pub(crate) fn pop_input<'b>(&'b mut self) -> Option<SpannedWord<'a>> {
106 if self.is_finished() {
107 None
108 } else {
109 self.cursor += 1;
110 Some(self.words[self.cursor - 1])
111 }
112 }
113
114 pub(crate) fn is_finished(&self) -> bool {
115 self.cursor >= self.words.len()
116 }
117
118 #[allow(dead_code)] pub(crate) fn advance(&mut self, advance: usize) {
120 self.cursor += advance;
121 debug_assert!(self.cursor <= self.words.len());
122 }
123
124 pub fn push_str(&mut self, arg: &str, span: Span) {
125 let raw_slice: u128 = unsafe { std::mem::transmute(arg) };
126 self.push_arg(raw_slice, span);
127 }
128
129 pub fn push_ref<T>(&mut self, arg: &T, span: Span) {
130 let raw_reference: usize = unsafe { std::mem::transmute(arg) };
131 self.push_arg(raw_reference, span);
132 }
133
134 pub fn push_arg<T: NoUninit>(&mut self, arg: T, span: Span) {
135 let arg_layout = Layout::new::<T>();
137
138 let (new_layout, offset) = self.argument_layout.extend(arg_layout).unwrap();
140 self.argument_layout = new_layout;
141 self.arguments.resize(offset, 0);
142
143 let bytes: &[u8] = bytemuck::bytes_of(&arg);
145 debug_assert_eq!(arg_layout.size(), bytes.len());
146 self.arguments.put_slice(bytes);
147 self.argument_spans.push(span);
148 }
149}
150
151pub type DispatchFunction = fn(&[u8], &[Span]) -> CommandDispatchResult;
152
153pub type CommandResult = result::Result<(), String>;
154
155#[derive(Debug)]
156pub enum CommandParseResult {
157 Ok,
158 Err {
159 span: Span,
160 errmsg: String,
161 continue_parsing: bool,
162 },
163}
164
165#[derive(Debug)]
166pub enum CommandDispatchResult {
167 Success(CommandResult),
168 ParseError {
169 span: Span,
170 errmsg: String,
171 continue_parsing: bool,
172 },
173 UnknownCommand,
174 IncompleteCommand,
175 TooManyArguments,
176}