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