1#![allow(clippy::uninlined_format_args, clippy::needless_borrow)]
9#![forbid(unsafe_code, future_incompatible)]
10#![no_std]
11
12extern crate alloc;
13
14#[cfg(any(test, feature = "std"))]
15extern crate std;
16
17use alloc::vec::Vec;
18
19pub mod attrs;
20mod parser;
21
22pub use parser::*;
23
24pub fn write_extend_vec(f: impl XimWrite, out: &mut Vec<u8>) {
25 let from = out.len();
26 out.extend(core::iter::repeat_n(0, f.size()));
27 f.write(&mut Writer::new(&mut out[from..]));
28}
29
30pub fn write_to_vec(f: impl XimWrite) -> Vec<u8> {
31 let mut out: Vec<u8> = core::iter::repeat_n(0, f.size()).collect();
32 f.write(&mut Writer::new(&mut out));
33 out
34}
35
36#[cfg(test)]
37mod tests {
38 use crate::{parser::*, write_to_vec};
39 use alloc::vec;
40 use alloc::vec::Vec;
41 use pretty_assertions::assert_eq;
42
43 #[cfg(target_endian = "little")]
44 #[test]
45 fn read_connect_req() {
46 let req: Request = read(b"\x01\x00\x00\x00\x6c\x00\x00\x00\x00\x00\x00\x00").unwrap();
47
48 assert_eq!(
49 req,
50 Request::Connect {
51 endian: Endian::Native,
52 client_auth_protocol_names: vec![],
53 client_minor_protocol_version: 0,
54 client_major_protocol_version: 0,
55 }
56 );
57 }
58
59 #[test]
60 fn read_open() {
61 let req = read::<Request>(&[
62 30, 0, 2, 0, 5, 101, 110, 95, 85, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 ])
64 .unwrap();
65 assert_eq!(
66 req,
67 Request::Open {
68 locale: "en_US".into(),
69 }
70 );
71 }
72
73 #[test]
74 fn read_query() {
75 let req = read::<Request>(&[
76 40, 0, 5, 0, 0, 0, 13, 0, 12, 88, 73, 77, 95, 69, 88, 84, 95, 77, 79, 86, 69, 0, 0, 0,
77 ])
78 .unwrap();
79 assert_eq!(
80 req,
81 Request::QueryExtension {
82 input_method_id: 0,
83 extensions: vec!["XIM_EXT_MOVE".into(),],
84 }
85 );
86 }
87
88 #[test]
89 fn read_input_styles() {
90 let styles: InputStyleList = read(&[1, 0, 0, 0, 4, 1, 0, 0]).unwrap();
91
92 assert_eq!(
93 styles,
94 InputStyleList {
95 styles: vec![InputStyle::PREEDIT_POSITION | InputStyle::STATUS_AREA]
96 }
97 );
98 }
99
100 #[test]
101 fn commit() {
102 let req = Request::Commit {
103 input_method_id: 1,
104 input_context_id: 1,
105 data: CommitData::Chars {
106 commited: xim_ctext::utf8_to_compound_text("맘"),
107 syncronous: false,
108 },
109 };
110
111 write_to_vec(req);
112 }
113
114 #[test]
115 fn set_event_mask() {
116 let req = Request::SetEventMask {
117 input_method_id: 2,
118 input_context_id: 1,
119 forward_event_mask: 3,
120 synchronous_event_mask: 4294967292,
121 };
122 let out = write_to_vec(&req);
123 assert_eq!(
124 out,
125 [37, 0, 3, 0, 2, 0, 1, 0, 3, 0, 0, 0, 252, 255, 255, 255]
126 );
127 assert_eq!(req, read::<Request>(&out).unwrap());
128 }
129
130 #[test]
131 fn attr_size() {
132 let list = InputStyleList {
133 styles: vec![InputStyle::PREEDIT_POSITION | InputStyle::STATUS_AREA],
134 };
135
136 assert_eq!(list.size(), 8);
137
138 let attr = Attribute {
139 id: 0,
140 value: write_to_vec(list),
141 };
142
143 assert_eq!(attr.size(), 12);
144 }
145
146 #[test]
147 fn im_reply() {
148 let req = Request::GetImValuesReply {
149 input_method_id: 3,
150 im_attributes: vec![Attribute {
151 id: 0,
152 value: write_to_vec(InputStyleList {
153 styles: vec![InputStyle::PREEDIT_POSITION | InputStyle::STATUS_AREA],
154 }),
155 }],
156 };
157
158 let out = write_to_vec(&req);
159 assert_eq!(req.size(), out.len());
160
161 let new_req = read(&out).unwrap();
162
163 assert_eq!(req, new_req);
164 }
165
166 #[test]
167 fn spot_attr() {
168 let value = [4, 0, 4, 0, 0, 0, 0, 0];
169
170 let attr = read::<Attribute>(&value).unwrap();
171
172 assert_eq!(attr.id, 4);
173 assert_eq!(read::<Point>(&attr.value).unwrap(), Point { x: 0, y: 0 });
174 }
175
176 #[test]
177 fn read_error() {
178 let req: Request = read(&[
179 20, 0, 7, 0, 2, 0, 1, 0, 3, 0, 2, 0, 16, 0, 0, 0, 105, 110, 118, 97, 108, 105, 100, 32,
180 105, 109, 32, 115, 116, 121, 108, 101,
181 ])
182 .unwrap();
183
184 assert_eq!(
185 req,
186 Request::Error {
187 input_method_id: 2,
188 input_context_id: 1,
189 flag: ErrorFlag::INPUT_METHOD_ID_VALID | ErrorFlag::INPUT_CONTEXT_ID_VALID,
190 code: ErrorCode::BadStyle,
191 detail: "invalid im style".into(),
192 }
193 );
194 }
195
196 #[test]
197 fn write_get_im_values() {
198 let req = Request::GetImValues {
199 input_method_id: 1,
200 im_attributes: vec![0],
201 };
202
203 let out = write_to_vec(&req);
204
205 assert_eq!(out.len(), req.size());
206 }
207
208 #[test]
209 fn write_forward_event() {
210 let req = Request::ForwardEvent {
211 input_method_id: 0,
212 input_context_id: 0,
213 flag: ForwardEventFlag::empty(),
214 serial_number: 0,
215 xev: XEvent {
216 response_type: 0,
217 detail: 0,
218 sequence: 0,
219 time: 0,
220 root: 0,
221 event: 0,
222 child: 0,
223 root_x: 0,
224 root_y: 0,
225 event_x: 0,
226 event_y: 0,
227 state: 0,
228 same_screen: false,
229 },
230 };
231 assert_eq!(req.size(), 4 + 8 + 32);
232
233 let out = write_to_vec(&req);
234 assert!(out.starts_with(b"\x3c\x00\x0a\x00"));
235 }
236
237 #[test]
238 fn write_create_ic() {
239 let req = Request::CreateIc {
240 input_method_id: 2,
241 ic_attributes: Vec::new(),
242 };
243 let out = write_to_vec(&req);
244 assert_eq!(out, b"\x32\x00\x01\x00\x02\x00\x00\x00");
245 }
246
247 #[test]
248 fn write_connect_reply() {
249 let req = Request::ConnectReply {
250 server_minor_protocol_version: 0,
251 server_major_protocol_version: 1,
252 };
253 let out = write_to_vec(&req);
254 assert_eq!(out, b"\x02\x00\x01\x00\x01\x00\x00\x00");
255 }
256
257 const OPEN_REPLY: &[u8] = b"\x1f\x00\x59\x00\x01\x00\x18\x00\x00\x00\x0a\x00\x0f\x00\x71\x75\x65\x72\x79\x49\x6e\x70\x75\x74\x53\x74\x79\x6c\x65\x00\x00\x00\x44\x01\x00\x00\x01\x00\x03\x00\x0a\x00\x69\x6e\x70\x75\x74\x53\x74\x79\x6c\x65\x02\x00\x05\x00\x0c\x00\x63\x6c\x69\x65\x6e\x74\x57\x69\x6e\x64\x6f\x77\x00\x00\x03\x00\x05\x00\x0b\x00\x66\x6f\x63\x75\x73\x57\x69\x6e\x64\x6f\x77\x00\x00\x00\x04\x00\x03\x00\x0c\x00\x66\x69\x6c\x74\x65\x72\x45\x76\x65\x6e\x74\x73\x00\x00\x05\x00\xff\x7f\x11\x00\x70\x72\x65\x65\x64\x69\x74\x41\x74\x74\x72\x69\x62\x75\x74\x65\x73\x00\x06\x00\xff\x7f\x10\x00\x73\x74\x61\x74\x75\x73\x41\x74\x74\x72\x69\x62\x75\x74\x65\x73\x00\x00\x07\x00\x0d\x00\x07\x00\x66\x6f\x6e\x74\x53\x65\x74\x00\x00\x00\x08\x00\x0b\x00\x04\x00\x61\x72\x65\x61\x00\x00\x09\x00\x0b\x00\x0a\x00\x61\x72\x65\x61\x4e\x65\x65\x64\x65\x64\x0a\x00\x03\x00\x08\x00\x63\x6f\x6c\x6f\x72\x4d\x61\x70\x00\x00\x0b\x00\x03\x00\x0b\x00\x73\x74\x64\x43\x6f\x6c\x6f\x72\x4d\x61\x70\x00\x00\x00\x0c\x00\x03\x00\x0a\x00\x66\x6f\x72\x65\x67\x72\x6f\x75\x6e\x64\x0d\x00\x03\x00\x0a\x00\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x0e\x00\x03\x00\x10\x00\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x50\x69\x78\x6d\x61\x70\x00\x00\x0f\x00\x0c\x00\x0c\x00\x73\x70\x6f\x74\x4c\x6f\x63\x61\x74\x69\x6f\x6e\x00\x00\x10\x00\x03\x00\x09\x00\x6c\x69\x6e\x65\x53\x70\x61\x63\x65\x00\x11\x00\x00\x00\x15\x00\x73\x65\x70\x61\x72\x61\x74\x6f\x72\x6f\x66\x4e\x65\x73\x74\x65\x64\x4c\x69\x73\x74\x00";
258
259 fn open_reply_value() -> Request {
260 Request::OpenReply {
261 input_method_id: 1,
262 im_attrs: vec![Attr {
263 id: 0,
264 ty: AttrType::Style,
265 name: AttributeName::QueryInputStyle,
266 }],
267 ic_attrs: vec![
268 Attr {
269 id: 1,
270 ty: AttrType::Long,
271 name: AttributeName::InputStyle,
272 },
273 Attr {
274 id: 2,
275 ty: AttrType::Window,
276 name: AttributeName::ClientWindow,
277 },
278 Attr {
279 id: 3,
280 ty: AttrType::Window,
281 name: AttributeName::FocusWindow,
282 },
283 Attr {
284 id: 4,
285 ty: AttrType::Long,
286 name: AttributeName::FilterEvents,
287 },
288 Attr {
289 id: 5,
290 ty: AttrType::NestedList,
291 name: AttributeName::PreeditAttributes,
292 },
293 Attr {
294 id: 6,
295 ty: AttrType::NestedList,
296 name: AttributeName::StatusAttributes,
297 },
298 Attr {
299 id: 7,
300 ty: AttrType::XFontSet,
301 name: AttributeName::FontSet,
302 },
303 Attr {
304 id: 8,
305 ty: AttrType::XRectangle,
306 name: AttributeName::Area,
307 },
308 Attr {
309 id: 9,
310 ty: AttrType::XRectangle,
311 name: AttributeName::AreaNeeded,
312 },
313 Attr {
314 id: 10,
315 ty: AttrType::Long,
316 name: AttributeName::ColorMap,
317 },
318 Attr {
319 id: 11,
320 ty: AttrType::Long,
321 name: AttributeName::StdColorMap,
322 },
323 Attr {
324 id: 12,
325 ty: AttrType::Long,
326 name: AttributeName::Foreground,
327 },
328 Attr {
329 id: 13,
330 ty: AttrType::Long,
331 name: AttributeName::Background,
332 },
333 Attr {
334 id: 14,
335 ty: AttrType::Long,
336 name: AttributeName::BackgroundPixmap,
337 },
338 Attr {
339 id: 15,
340 ty: AttrType::XPoint,
341 name: AttributeName::SpotLocation,
342 },
343 Attr {
344 id: 16,
345 ty: AttrType::Long,
346 name: AttributeName::LineSpace,
347 },
348 Attr {
349 id: 17,
350 ty: AttrType::Separator,
351 name: AttributeName::SeparatorofNestedList,
352 },
353 ],
354 }
355 }
356
357 #[test]
358 fn read_open_reply() {
359 assert_eq!(read::<Request>(OPEN_REPLY).unwrap(), open_reply_value());
360 }
361
362 #[test]
363 fn size_open_reply() {
364 assert_eq!(open_reply_value().size(), OPEN_REPLY.len());
365 }
366
367 #[test]
368 fn write_open_reply() {
369 let value = open_reply_value();
370 let out = write_to_vec(&value);
371 assert_eq!(OPEN_REPLY.len(), out.len());
372 assert_eq!(OPEN_REPLY, out);
373 let new: Request = read(&out).unwrap();
374 assert_eq!(value, new);
375 }
376}