1 use crate::backend::c;
2 use crate::{backend, io};
3 use bitflags::bitflags;
4 
5 /// `struct termios` for use with [`tcgetattr`] and [`tcsetattr`].
6 ///
7 /// [`tcgetattr`]: crate::termios::tcgetattr
8 /// [`tcsetattr`]: crate::termios::tcsetattr
9 #[repr(C)]
10 #[derive(Clone)]
11 pub struct Termios {
12     /// How is input interpreted?
13     #[doc(alias = "c_iflag")]
14     pub input_modes: InputModes,
15 
16     /// How is output translated?
17     #[doc(alias = "c_oflag")]
18     pub output_modes: OutputModes,
19 
20     /// Low-level configuration flags.
21     #[doc(alias = "c_cflag")]
22     pub control_modes: ControlModes,
23 
24     /// High-level configuration flags.
25     #[doc(alias = "c_lflag")]
26     pub local_modes: LocalModes,
27 
28     /// Line discipline.
29     #[doc(alias = "c_line")]
30     #[cfg(not(all(linux_raw, any(target_arch = "powerpc", target_arch = "powerpc64"))))]
31     #[cfg(any(
32         linux_like,
33         target_env = "newlib",
34         target_os = "fuchsia",
35         target_os = "haiku",
36         target_os = "redox"
37     ))]
38     pub line_discipline: c::cc_t,
39 
40     /// How are various special control codes handled?
41     #[doc(alias = "c_cc")]
42     #[cfg(not(target_os = "haiku"))]
43     pub special_codes: SpecialCodes,
44 
45     #[cfg(target_os = "nto")]
46     pub(crate) __reserved: [c::c_uint; 3],
47 
48     /// Line discipline.
49     // On PowerPC, this field comes after `c_cc`.
50     #[doc(alias = "c_line")]
51     #[cfg(all(linux_raw, any(target_arch = "powerpc", target_arch = "powerpc64")))]
52     pub line_discipline: c::cc_t,
53 
54     /// See the `input_speed` and `set_input_seed` functions.
55     ///
56     /// On Linux and BSDs, this is the arbitrary integer speed value. On all
57     /// other platforms, this is the encoded speed value.
58     #[cfg(not(any(solarish, all(libc, target_env = "newlib"), target_os = "aix")))]
59     pub(crate) input_speed: c::speed_t,
60 
61     /// See the `output_speed` and `set_output_seed` functions.
62     ///
63     /// On Linux and BSDs, this is the integer speed value. On all other
64     /// platforms, this is the encoded speed value.
65     #[cfg(not(any(solarish, all(libc, target_env = "newlib"), target_os = "aix")))]
66     pub(crate) output_speed: c::speed_t,
67 
68     /// How are various special control codes handled?
69     #[doc(alias = "c_cc")]
70     #[cfg(target_os = "haiku")]
71     pub special_codes: SpecialCodes,
72 }
73 
74 impl Termios {
75     /// `cfmakeraw(self)`—Set a `Termios` value to the settings for “raw” mode.
76     ///
77     /// In raw mode, input is available a byte at a time, echoing is disabled,
78     /// and special terminal input and output codes are disabled.
79     #[cfg(not(target_os = "nto"))]
80     #[doc(alias = "cfmakeraw")]
81     #[inline]
make_raw(&mut self)82     pub fn make_raw(&mut self) {
83         backend::termios::syscalls::cfmakeraw(self)
84     }
85 
86     /// Return the input communication speed.
87     ///
88     /// Unlike the `c_ispeed` field in glibc and others, this returns the
89     /// integer value of the speed, rather than the `B*` encoded constant
90     /// value.
91     #[doc(alias = "c_ispeed")]
92     #[doc(alias = "cfgetispeed")]
93     #[doc(alias = "cfgetspeed")]
94     #[inline]
input_speed(&self) -> u3295     pub fn input_speed(&self) -> u32 {
96         // On Linux and BSDs, `input_speed` is the arbitrary integer speed.
97         #[cfg(any(linux_kernel, bsd))]
98         {
99             debug_assert!(u32::try_from(self.input_speed).is_ok());
100             self.input_speed as u32
101         }
102 
103         // On illumos, `input_speed` is not present.
104         #[cfg(any(solarish, all(libc, target_env = "newlib"), target_os = "aix"))]
105         unsafe {
106             speed::decode(c::cfgetispeed(crate::utils::as_ptr(self).cast())).unwrap()
107         }
108 
109         // On other platforms, it's the encoded speed.
110         #[cfg(not(any(
111             linux_kernel,
112             bsd,
113             solarish,
114             all(libc, target_env = "newlib"),
115             target_os = "aix"
116         )))]
117         {
118             speed::decode(self.input_speed).unwrap()
119         }
120     }
121 
122     /// Return the output communication speed.
123     ///
124     /// Unlike the `c_ospeed` field in glibc and others, this returns the
125     /// arbitrary integer value of the speed, rather than the `B*` encoded
126     /// constant value.
127     #[inline]
output_speed(&self) -> u32128     pub fn output_speed(&self) -> u32 {
129         // On Linux and BSDs, `input_speed` is the arbitrary integer speed.
130         #[cfg(any(linux_kernel, bsd))]
131         {
132             debug_assert!(u32::try_from(self.output_speed).is_ok());
133             self.output_speed as u32
134         }
135 
136         // On illumos, `output_speed` is not present.
137         #[cfg(any(solarish, all(libc, target_env = "newlib"), target_os = "aix"))]
138         unsafe {
139             speed::decode(c::cfgetospeed(crate::utils::as_ptr(self).cast())).unwrap()
140         }
141 
142         // On other platforms, it's the encoded speed.
143         #[cfg(not(any(
144             linux_kernel,
145             bsd,
146             solarish,
147             all(libc, target_env = "newlib"),
148             target_os = "aix"
149         )))]
150         {
151             speed::decode(self.output_speed).unwrap()
152         }
153     }
154 
155     /// Set the input and output communication speeds.
156     ///
157     /// Unlike the `c_ispeed` and `c_ospeed` fields in glibc and others, this
158     /// takes the arbitrary integer value of the speed, rather than the `B*`
159     /// encoded constant value. Not all implementations support all integer
160     /// values; use the constants in the [`speed`] module for likely-supported
161     /// speeds.
162     #[cfg(not(target_os = "nto"))]
163     #[doc(alias = "cfsetspeed")]
164     #[doc(alias = "CBAUD")]
165     #[doc(alias = "CBAUDEX")]
166     #[doc(alias = "CIBAUD")]
167     #[doc(alias = "CIBAUDEX")]
168     #[inline]
set_speed(&mut self, new_speed: u32) -> io::Result<()>169     pub fn set_speed(&mut self, new_speed: u32) -> io::Result<()> {
170         backend::termios::syscalls::set_speed(self, new_speed)
171     }
172 
173     /// Set the input communication speed.
174     ///
175     /// Unlike the `c_ispeed` field in glibc and others, this takes the
176     /// arbitrary integer value of the speed, rather than the `B*` encoded
177     /// constant value. Not all implementations support all integer values; use
178     /// the constants in the [`speed`] module for known-supported speeds.
179     ///
180     /// On some platforms, changing the input speed changes the output speed
181     /// to the same speed.
182     #[doc(alias = "c_ispeed")]
183     #[doc(alias = "cfsetispeed")]
184     #[doc(alias = "CIBAUD")]
185     #[doc(alias = "CIBAUDEX")]
186     #[inline]
set_input_speed(&mut self, new_speed: u32) -> io::Result<()>187     pub fn set_input_speed(&mut self, new_speed: u32) -> io::Result<()> {
188         backend::termios::syscalls::set_input_speed(self, new_speed)
189     }
190 
191     /// Set the output communication speed.
192     ///
193     /// Unlike the `c_ospeed` field in glibc and others, this takes the
194     /// arbitrary integer value of the speed, rather than the `B*` encoded
195     /// constant value. Not all implementations support all integer values; use
196     /// the constants in the [`speed`] module for known-supported speeds.
197     ///
198     /// On some platforms, changing the output speed changes the input speed
199     /// to the same speed.
200     #[doc(alias = "c_ospeed")]
201     #[doc(alias = "cfsetospeed")]
202     #[doc(alias = "CBAUD")]
203     #[doc(alias = "CBAUDEX")]
204     #[inline]
set_output_speed(&mut self, new_speed: u32) -> io::Result<()>205     pub fn set_output_speed(&mut self, new_speed: u32) -> io::Result<()> {
206         backend::termios::syscalls::set_output_speed(self, new_speed)
207     }
208 }
209 
210 impl core::fmt::Debug for Termios {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result211     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
212         let mut d = f.debug_struct("Termios");
213         d.field("input_modes", &self.input_modes);
214         d.field("output_modes", &self.output_modes);
215         d.field("control_modes", &self.control_modes);
216         d.field("local_modes", &self.local_modes);
217         #[cfg(any(
218             linux_like,
219             target_env = "newlib",
220             target_os = "fuchsia",
221             target_os = "haiku",
222             target_os = "redox"
223         ))]
224         {
225             d.field("line_discipline", &self.line_discipline);
226         }
227         d.field("special_codes", &self.special_codes);
228         d.field("input_speed", &self.input_speed());
229         d.field("output_speed", &self.output_speed());
230         d.finish()
231     }
232 }
233 
234 bitflags! {
235     /// Flags controlling terminal input.
236     #[repr(transparent)]
237     #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
238     pub struct InputModes: c::tcflag_t {
239         /// `IGNBRK`
240         const IGNBRK = c::IGNBRK;
241 
242         /// `BRKINT`
243         const BRKINT = c::BRKINT;
244 
245         /// `IGNPAR`
246         const IGNPAR = c::IGNPAR;
247 
248         /// `PARMRK`
249         const PARMRK = c::PARMRK;
250 
251         /// `INPCK`
252         const INPCK = c::INPCK;
253 
254         /// `ISTRIP`
255         const ISTRIP = c::ISTRIP;
256 
257         /// `INLCR`
258         const INLCR = c::INLCR;
259 
260         /// `IGNCR`
261         const IGNCR = c::IGNCR;
262 
263         /// `ICRNL`
264         const ICRNL = c::ICRNL;
265 
266         /// `IUCLC`
267         #[cfg(any(linux_kernel, solarish, target_os = "aix", target_os = "haiku", target_os = "nto"))]
268         const IUCLC = c::IUCLC;
269 
270         /// `IXON`
271         const IXON = c::IXON;
272 
273         /// `IXANY`
274         #[cfg(not(target_os = "redox"))]
275         const IXANY = c::IXANY;
276 
277         /// `IXOFF`
278         const IXOFF = c::IXOFF;
279 
280         /// `IMAXBEL`
281         #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
282         const IMAXBEL = c::IMAXBEL;
283 
284         /// `IUTF8`
285         #[cfg(not(any(
286             freebsdlike,
287             netbsdlike,
288             solarish,
289             target_os = "aix",
290             target_os = "emscripten",
291             target_os = "haiku",
292             target_os = "hurd",
293             target_os = "redox",
294         )))]
295         const IUTF8 = c::IUTF8;
296 
297         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
298         const _ = !0;
299     }
300 }
301 
302 bitflags! {
303     /// Flags controlling terminal output.
304     #[repr(transparent)]
305     #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
306     pub struct OutputModes: c::tcflag_t {
307         /// `OPOST`
308         const OPOST = c::OPOST;
309 
310         /// `OLCUC`
311         #[cfg(not(any(
312             apple,
313             freebsdlike,
314             target_os = "aix",
315             target_os = "netbsd",
316             target_os = "redox",
317         )))]
318         const OLCUC = c::OLCUC;
319 
320         /// `ONLCR`
321         const ONLCR = c::ONLCR;
322 
323         /// `OCRNL`
324         const OCRNL = c::OCRNL;
325 
326         /// `ONOCR`
327         const ONOCR = c::ONOCR;
328 
329         /// `ONLRET`
330         const ONLRET = c::ONLRET;
331 
332         /// `OFILL`
333         #[cfg(not(bsd))]
334         const OFILL = c::OFILL;
335 
336         /// `OFDEL`
337         #[cfg(not(bsd))]
338         const OFDEL = c::OFDEL;
339 
340         /// `NLDLY`
341         #[cfg(not(any(bsd, solarish, target_os = "redox")))]
342         const NLDLY = c::NLDLY;
343 
344         /// `NL0`
345         #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
346         const NL0 = c::NL0;
347 
348         /// `NL1`
349         #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
350         const NL1 = c::NL1;
351 
352         /// `CRDLY`
353         #[cfg(not(any(bsd, solarish, target_os = "redox")))]
354         const CRDLY = c::CRDLY;
355 
356         /// `CR0`
357         #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
358         const CR0 = c::CR0;
359 
360         /// `CR1`
361         #[cfg(not(any(
362             target_env = "musl",
363             bsd,
364             solarish,
365             target_os = "emscripten",
366             target_os = "fuchsia",
367             target_os = "redox",
368         )))]
369         const CR1 = c::CR1;
370 
371         /// `CR2`
372         #[cfg(not(any(
373             target_env = "musl",
374             bsd,
375             solarish,
376             target_os = "emscripten",
377             target_os = "fuchsia",
378             target_os = "redox",
379         )))]
380         const CR2 = c::CR2;
381 
382         /// `CR3`
383         #[cfg(not(any(
384             target_env = "musl",
385             bsd,
386             solarish,
387             target_os = "emscripten",
388             target_os = "fuchsia",
389             target_os = "redox",
390         )))]
391         const CR3 = c::CR3;
392 
393         /// `TABDLY`
394         #[cfg(not(any(
395             netbsdlike,
396             solarish,
397             target_os = "dragonfly",
398             target_os = "redox",
399         )))]
400         const TABDLY = c::TABDLY;
401 
402         /// `TAB0`
403         #[cfg(not(any(
404             netbsdlike,
405             solarish,
406             target_os = "dragonfly",
407             target_os = "fuchsia",
408             target_os = "redox",
409         )))]
410         const TAB0 = c::TAB0;
411 
412         /// `TAB1`
413         #[cfg(not(any(
414             target_env = "musl",
415             bsd,
416             solarish,
417             target_os = "emscripten",
418             target_os = "fuchsia",
419             target_os = "redox",
420         )))]
421         const TAB1 = c::TAB1;
422 
423         /// `TAB2`
424         #[cfg(not(any(
425             target_env = "musl",
426             bsd,
427             solarish,
428             target_os = "emscripten",
429             target_os = "fuchsia",
430             target_os = "redox",
431         )))]
432         const TAB2 = c::TAB2;
433 
434         /// `TAB3`
435         #[cfg(not(any(
436             target_env = "musl",
437             bsd,
438             solarish,
439             target_os = "emscripten",
440             target_os = "fuchsia",
441             target_os = "redox",
442         )))]
443         const TAB3 = c::TAB3;
444 
445         /// `XTABS`
446         #[cfg(not(any(
447             bsd,
448             solarish,
449             target_os = "aix",
450             target_os = "haiku",
451             target_os = "redox",
452         )))]
453         const XTABS = c::XTABS;
454 
455         /// `BSDLY`
456         #[cfg(not(any(bsd, solarish, target_os = "redox")))]
457         const BSDLY = c::BSDLY;
458 
459         /// `BS0`
460         #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
461         const BS0 = c::BS0;
462 
463         /// `BS1`
464         #[cfg(not(any(
465             target_env = "musl",
466             bsd,
467             solarish,
468             target_os = "emscripten",
469             target_os = "fuchsia",
470             target_os = "redox",
471         )))]
472         const BS1 = c::BS1;
473 
474         /// `FFDLY`
475         #[cfg(not(any(bsd, solarish, target_os = "redox")))]
476         const FFDLY = c::FFDLY;
477 
478         /// `FF0`
479         #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
480         const FF0 = c::FF0;
481 
482         /// `FF1`
483         #[cfg(not(any(
484             target_env = "musl",
485             bsd,
486             solarish,
487             target_os = "emscripten",
488             target_os = "fuchsia",
489             target_os = "redox",
490         )))]
491         const FF1 = c::FF1;
492 
493         /// `VTDLY`
494         #[cfg(not(any(bsd, solarish, target_os = "redox")))]
495         const VTDLY = c::VTDLY;
496 
497         /// `VT0`
498         #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
499         const VT0 = c::VT0;
500 
501         /// `VT1`
502         #[cfg(not(any(
503             target_env = "musl",
504             bsd,
505             solarish,
506             target_os = "emscripten",
507             target_os = "fuchsia",
508             target_os = "redox",
509         )))]
510         const VT1 = c::VT1;
511 
512         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
513         const _ = !0;
514     }
515 }
516 
517 bitflags! {
518     /// Flags controlling special terminal modes.
519     ///
520     /// `CBAUD`, `CBAUDEX`, `CIBAUD`, and `CIBAUDEX` are not defined here,
521     /// because they're handled automatically by [`Termios::set_speed`] and
522     /// related functions.
523     #[repr(transparent)]
524     #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
525     pub struct ControlModes: c::tcflag_t {
526         /// `CSIZE`
527         const CSIZE = c::CSIZE;
528 
529         /// `CS5`
530         const CS5 = c::CS5;
531 
532         /// `CS6`
533         const CS6 = c::CS6;
534 
535         /// `CS7`
536         const CS7 = c::CS7;
537 
538         /// `CS8`
539         const CS8 = c::CS8;
540 
541         /// `CSTOPB`
542         const CSTOPB = c::CSTOPB;
543 
544         /// `CREAD`
545         const CREAD = c::CREAD;
546 
547         /// `PARENB`
548         const PARENB = c::PARENB;
549 
550         /// `PARODD`
551         const PARODD = c::PARODD;
552 
553         /// `HUPCL`
554         const HUPCL = c::HUPCL;
555 
556         /// `CLOCAL`
557         const CLOCAL = c::CLOCAL;
558 
559         /// `CRTSCTS`
560         #[cfg(not(any(target_os = "aix", target_os = "nto", target_os = "redox")))]
561         const CRTSCTS = c::CRTSCTS;
562 
563         /// `CMSPAR`
564         #[cfg(not(any(
565             bsd,
566             solarish,
567             target_os = "aix",
568             target_os = "emscripten",
569             target_os = "haiku",
570             target_os = "hurd",
571             target_os = "nto",
572             target_os = "redox",
573         )))]
574         const CMSPAR = c::CMSPAR;
575 
576         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
577         const _ = !0;
578     }
579 }
580 
581 bitflags! {
582     /// Flags controlling “local” terminal modes.
583     #[repr(transparent)]
584     #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
585     pub struct LocalModes: c::tcflag_t {
586         /// `XCASE`
587         #[cfg(any(linux_kernel, target_arch = "s390x", target_os = "haiku"))]
588         const XCASE = c::XCASE;
589 
590         /// `ECHOCTL`
591         #[cfg(not(target_os = "redox"))]
592         const ECHOCTL = c::ECHOCTL;
593 
594         /// `ECHOPRT`
595         #[cfg(not(any(target_os = "nto", target_os = "redox")))]
596         const ECHOPRT = c::ECHOPRT;
597 
598         /// `ECHOKE`
599         #[cfg(not(target_os = "redox"))]
600         const ECHOKE = c::ECHOKE;
601 
602         /// `FLUSHO`
603         #[cfg(not(any(target_os = "nto", target_os = "redox")))]
604         const FLUSHO = c::FLUSHO;
605 
606         /// `PENDIN`
607         #[cfg(not(any(target_os = "nto", target_os = "redox")))]
608         const PENDIN = c::PENDIN;
609 
610         /// `EXTPROC`
611         #[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "nto", target_os = "redox")))]
612         const EXTPROC = c::EXTPROC;
613 
614         /// `ISIG`
615         const ISIG = c::ISIG;
616 
617         /// `ICANON`—A flag for the `c_lflag` field of [`Termios`] indicating
618         /// canonical mode.
619         const ICANON = c::ICANON;
620 
621         /// `ECHO`
622         const ECHO = c::ECHO;
623 
624         /// `ECHOE`
625         const ECHOE = c::ECHOE;
626 
627         /// `ECHOK`
628         const ECHOK = c::ECHOK;
629 
630         /// `ECHONL`
631         const ECHONL = c::ECHONL;
632 
633         /// `NOFLSH`
634         const NOFLSH = c::NOFLSH;
635 
636         /// `TOSTOP`
637         const TOSTOP = c::TOSTOP;
638 
639         /// `IEXTEN`
640         const IEXTEN = c::IEXTEN;
641 
642         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
643         const _ = !0;
644     }
645 }
646 
647 /// Speeds for use with [`Termios::set_input_speed`] and
648 /// [`Termios::set_output_speed`].
649 ///
650 /// Unlike in some platforms' libc APIs, these always have the same numerical
651 /// value as their names; for example, `B50` has the value `50`, and so on.
652 /// Consequently, it's not necessary to use them. They are provided here
653 /// because they help identify speeds which are likely to be supported, on
654 /// platforms which don't support arbitrary speeds.
655 pub mod speed {
656     #[cfg(not(bsd))]
657     use crate::backend::c;
658 
659     /// `B0`
660     pub const B0: u32 = 0;
661 
662     /// `B50`
663     pub const B50: u32 = 50;
664 
665     /// `B75`
666     pub const B75: u32 = 75;
667 
668     /// `B110`
669     pub const B110: u32 = 110;
670 
671     /// `B134`
672     pub const B134: u32 = 134;
673 
674     /// `B150`
675     pub const B150: u32 = 150;
676 
677     /// `B200`
678     pub const B200: u32 = 200;
679 
680     /// `B300`
681     pub const B300: u32 = 300;
682 
683     /// `B600`
684     pub const B600: u32 = 600;
685 
686     /// `B1200`
687     pub const B1200: u32 = 1200;
688 
689     /// `B1800`
690     pub const B1800: u32 = 1800;
691 
692     /// `B2400`
693     pub const B2400: u32 = 2400;
694 
695     /// `B4800`
696     pub const B4800: u32 = 4800;
697 
698     /// `B9600`
699     pub const B9600: u32 = 9600;
700 
701     /// `B19200`
702     #[doc(alias = "EXTA")]
703     pub const B19200: u32 = 19200;
704 
705     /// `B38400`
706     #[doc(alias = "EXTB")]
707     pub const B38400: u32 = 38400;
708 
709     /// `B57600`
710     #[cfg(not(target_os = "aix"))]
711     pub const B57600: u32 = 57600;
712 
713     /// `B115200`
714     #[cfg(not(target_os = "aix"))]
715     pub const B115200: u32 = 115_200;
716 
717     /// `B230400`
718     #[cfg(not(target_os = "aix"))]
719     pub const B230400: u32 = 230_400;
720 
721     /// `B460800`
722     #[cfg(not(any(
723         apple,
724         target_os = "aix",
725         target_os = "dragonfly",
726         target_os = "haiku",
727         target_os = "openbsd"
728     )))]
729     pub const B460800: u32 = 460_800;
730 
731     /// `B500000`
732     #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
733     pub const B500000: u32 = 500_000;
734 
735     /// `B576000`
736     #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
737     pub const B576000: u32 = 576_000;
738 
739     /// `B921600`
740     #[cfg(not(any(
741         apple,
742         target_os = "aix",
743         target_os = "dragonfly",
744         target_os = "haiku",
745         target_os = "openbsd"
746     )))]
747     pub const B921600: u32 = 921_600;
748 
749     /// `B1000000`
750     #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
751     pub const B1000000: u32 = 1_000_000;
752 
753     /// `B1152000`
754     #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
755     pub const B1152000: u32 = 1_152_000;
756 
757     /// `B1500000`
758     #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
759     pub const B1500000: u32 = 1_500_000;
760 
761     /// `B2000000`
762     #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
763     pub const B2000000: u32 = 2_000_000;
764 
765     /// `B2500000`
766     #[cfg(not(any(
767         target_arch = "sparc",
768         target_arch = "sparc64",
769         bsd,
770         target_os = "aix",
771         target_os = "haiku",
772         target_os = "solaris",
773     )))]
774     pub const B2500000: u32 = 2_500_000;
775 
776     /// `B3000000`
777     #[cfg(not(any(
778         target_arch = "sparc",
779         target_arch = "sparc64",
780         bsd,
781         target_os = "aix",
782         target_os = "haiku",
783         target_os = "solaris",
784     )))]
785     pub const B3000000: u32 = 3_000_000;
786 
787     /// `B3500000`
788     #[cfg(not(any(
789         target_arch = "sparc",
790         target_arch = "sparc64",
791         bsd,
792         target_os = "aix",
793         target_os = "haiku",
794         target_os = "solaris",
795     )))]
796     pub const B3500000: u32 = 3_500_000;
797 
798     /// `B4000000`
799     #[cfg(not(any(
800         target_arch = "sparc",
801         target_arch = "sparc64",
802         bsd,
803         target_os = "aix",
804         target_os = "haiku",
805         target_os = "solaris",
806     )))]
807     pub const B4000000: u32 = 4_000_000;
808 
809     /// Translate from a `c::speed_t` code to an arbitrary integer speed value
810     /// `u32`.
811     ///
812     /// On BSD platforms, integer speed values are already the same as their
813     /// encoded values, and on Linux platforms, we use `TCGETS2`/`TCSETS2`
814     /// and the `c_ispeed`/`c_ospeed`` fields, except that on Linux on
815     /// PowerPC on QEMU, `TCGETS2`/`TCSETS2` don't set `c_ispeed`/`c_ospeed`.
816     #[cfg(not(any(
817         bsd,
818         all(
819             linux_kernel,
820             not(any(target_arch = "powerpc", target_arch = "powerpc64"))
821         )
822     )))]
decode(encoded_speed: c::speed_t) -> Option<u32>823     pub(crate) const fn decode(encoded_speed: c::speed_t) -> Option<u32> {
824         match encoded_speed {
825             c::B0 => Some(0),
826             c::B50 => Some(50),
827             c::B75 => Some(75),
828             c::B110 => Some(110),
829             c::B134 => Some(134),
830             c::B150 => Some(150),
831             c::B200 => Some(200),
832             c::B300 => Some(300),
833             c::B600 => Some(600),
834             c::B1200 => Some(1200),
835             c::B1800 => Some(1800),
836             c::B2400 => Some(2400),
837             c::B4800 => Some(4800),
838             c::B9600 => Some(9600),
839             c::B19200 => Some(19200),
840             c::B38400 => Some(38400),
841             #[cfg(not(target_os = "aix"))]
842             c::B57600 => Some(57600),
843             #[cfg(not(target_os = "aix"))]
844             c::B115200 => Some(115_200),
845             #[cfg(not(any(target_os = "aix", target_os = "nto")))]
846             c::B230400 => Some(230_400),
847             #[cfg(not(any(
848                 apple,
849                 target_os = "aix",
850                 target_os = "dragonfly",
851                 target_os = "haiku",
852                 target_os = "nto",
853                 target_os = "openbsd"
854             )))]
855             c::B460800 => Some(460_800),
856             #[cfg(not(any(
857                 bsd,
858                 solarish,
859                 target_os = "aix",
860                 target_os = "haiku",
861                 target_os = "nto"
862             )))]
863             c::B500000 => Some(500_000),
864             #[cfg(not(any(
865                 bsd,
866                 solarish,
867                 target_os = "aix",
868                 target_os = "haiku",
869                 target_os = "nto"
870             )))]
871             c::B576000 => Some(576_000),
872             #[cfg(not(any(
873                 apple,
874                 target_os = "aix",
875                 target_os = "dragonfly",
876                 target_os = "haiku",
877                 target_os = "nto",
878                 target_os = "openbsd"
879             )))]
880             c::B921600 => Some(921_600),
881             #[cfg(not(any(
882                 bsd,
883                 target_os = "aix",
884                 target_os = "haiku",
885                 target_os = "nto",
886                 target_os = "solaris"
887             )))]
888             c::B1000000 => Some(1_000_000),
889             #[cfg(not(any(
890                 bsd,
891                 target_os = "aix",
892                 target_os = "haiku",
893                 target_os = "nto",
894                 target_os = "solaris"
895             )))]
896             c::B1152000 => Some(1_152_000),
897             #[cfg(not(any(
898                 bsd,
899                 target_os = "aix",
900                 target_os = "haiku",
901                 target_os = "nto",
902                 target_os = "solaris"
903             )))]
904             c::B1500000 => Some(1_500_000),
905             #[cfg(not(any(
906                 bsd,
907                 target_os = "aix",
908                 target_os = "haiku",
909                 target_os = "nto",
910                 target_os = "solaris"
911             )))]
912             c::B2000000 => Some(2_000_000),
913             #[cfg(not(any(
914                 target_arch = "sparc",
915                 target_arch = "sparc64",
916                 bsd,
917                 target_os = "aix",
918                 target_os = "haiku",
919                 target_os = "nto",
920                 target_os = "solaris",
921             )))]
922             c::B2500000 => Some(2_500_000),
923             #[cfg(not(any(
924                 target_arch = "sparc",
925                 target_arch = "sparc64",
926                 bsd,
927                 target_os = "aix",
928                 target_os = "haiku",
929                 target_os = "nto",
930                 target_os = "solaris",
931             )))]
932             c::B3000000 => Some(3_000_000),
933             #[cfg(not(any(
934                 target_arch = "sparc",
935                 target_arch = "sparc64",
936                 bsd,
937                 target_os = "aix",
938                 target_os = "haiku",
939                 target_os = "nto",
940                 target_os = "solaris",
941             )))]
942             c::B3500000 => Some(3_500_000),
943             #[cfg(not(any(
944                 target_arch = "sparc",
945                 target_arch = "sparc64",
946                 bsd,
947                 target_os = "aix",
948                 target_os = "haiku",
949                 target_os = "nto",
950                 target_os = "solaris",
951             )))]
952             c::B4000000 => Some(4_000_000),
953             _ => None,
954         }
955     }
956 
957     /// Translate from an arbitrary `u32` arbitrary integer speed value to a
958     /// `c::speed_t` code.
959     #[cfg(not(bsd))]
encode(speed: u32) -> Option<c::speed_t>960     pub(crate) const fn encode(speed: u32) -> Option<c::speed_t> {
961         match speed {
962             0 => Some(c::B0),
963             50 => Some(c::B50),
964             75 => Some(c::B75),
965             110 => Some(c::B110),
966             134 => Some(c::B134),
967             150 => Some(c::B150),
968             200 => Some(c::B200),
969             300 => Some(c::B300),
970             600 => Some(c::B600),
971             1200 => Some(c::B1200),
972             1800 => Some(c::B1800),
973             2400 => Some(c::B2400),
974             4800 => Some(c::B4800),
975             9600 => Some(c::B9600),
976             19200 => Some(c::B19200),
977             38400 => Some(c::B38400),
978             #[cfg(not(target_os = "aix"))]
979             57600 => Some(c::B57600),
980             #[cfg(not(target_os = "aix"))]
981             115_200 => Some(c::B115200),
982             #[cfg(not(any(target_os = "aix", target_os = "nto")))]
983             230_400 => Some(c::B230400),
984             #[cfg(not(any(
985                 apple,
986                 target_os = "aix",
987                 target_os = "dragonfly",
988                 target_os = "haiku",
989                 target_os = "nto",
990                 target_os = "openbsd",
991             )))]
992             460_800 => Some(c::B460800),
993             #[cfg(not(any(
994                 bsd,
995                 solarish,
996                 target_os = "aix",
997                 target_os = "haiku",
998                 target_os = "nto"
999             )))]
1000             500_000 => Some(c::B500000),
1001             #[cfg(not(any(
1002                 bsd,
1003                 solarish,
1004                 target_os = "aix",
1005                 target_os = "haiku",
1006                 target_os = "nto"
1007             )))]
1008             576_000 => Some(c::B576000),
1009             #[cfg(not(any(
1010                 apple,
1011                 target_os = "aix",
1012                 target_os = "dragonfly",
1013                 target_os = "haiku",
1014                 target_os = "nto",
1015                 target_os = "openbsd"
1016             )))]
1017             921_600 => Some(c::B921600),
1018             #[cfg(not(any(
1019                 bsd,
1020                 target_os = "aix",
1021                 target_os = "haiku",
1022                 target_os = "nto",
1023                 target_os = "solaris"
1024             )))]
1025             1_000_000 => Some(c::B1000000),
1026             #[cfg(not(any(
1027                 bsd,
1028                 target_os = "aix",
1029                 target_os = "haiku",
1030                 target_os = "nto",
1031                 target_os = "solaris"
1032             )))]
1033             1_152_000 => Some(c::B1152000),
1034             #[cfg(not(any(
1035                 bsd,
1036                 target_os = "aix",
1037                 target_os = "haiku",
1038                 target_os = "nto",
1039                 target_os = "solaris"
1040             )))]
1041             1_500_000 => Some(c::B1500000),
1042             #[cfg(not(any(
1043                 bsd,
1044                 target_os = "aix",
1045                 target_os = "haiku",
1046                 target_os = "nto",
1047                 target_os = "solaris"
1048             )))]
1049             2_000_000 => Some(c::B2000000),
1050             #[cfg(not(any(
1051                 target_arch = "sparc",
1052                 target_arch = "sparc64",
1053                 bsd,
1054                 target_os = "aix",
1055                 target_os = "haiku",
1056                 target_os = "nto",
1057                 target_os = "solaris",
1058             )))]
1059             2_500_000 => Some(c::B2500000),
1060             #[cfg(not(any(
1061                 target_arch = "sparc",
1062                 target_arch = "sparc64",
1063                 bsd,
1064                 target_os = "aix",
1065                 target_os = "haiku",
1066                 target_os = "nto",
1067                 target_os = "solaris",
1068             )))]
1069             3_000_000 => Some(c::B3000000),
1070             #[cfg(not(any(
1071                 target_arch = "sparc",
1072                 target_arch = "sparc64",
1073                 bsd,
1074                 target_os = "aix",
1075                 target_os = "haiku",
1076                 target_os = "nto",
1077                 target_os = "solaris",
1078             )))]
1079             3_500_000 => Some(c::B3500000),
1080             #[cfg(not(any(
1081                 target_arch = "sparc",
1082                 target_arch = "sparc64",
1083                 bsd,
1084                 target_os = "aix",
1085                 target_os = "haiku",
1086                 target_os = "nto",
1087                 target_os = "solaris",
1088             )))]
1089             4_000_000 => Some(c::B4000000),
1090             _ => None,
1091         }
1092     }
1093 }
1094 
1095 /// An array indexed by [`SpecialCodeIndex`] indicating the current values
1096 /// of various special control codes.
1097 #[repr(transparent)]
1098 #[derive(Clone, Debug)]
1099 pub struct SpecialCodes(pub(crate) [c::cc_t; c::NCCS as usize]);
1100 
1101 impl core::ops::Index<SpecialCodeIndex> for SpecialCodes {
1102     type Output = c::cc_t;
1103 
index(&self, index: SpecialCodeIndex) -> &Self::Output1104     fn index(&self, index: SpecialCodeIndex) -> &Self::Output {
1105         &self.0[index.0]
1106     }
1107 }
1108 
1109 impl core::ops::IndexMut<SpecialCodeIndex> for SpecialCodes {
index_mut(&mut self, index: SpecialCodeIndex) -> &mut Self::Output1110     fn index_mut(&mut self, index: SpecialCodeIndex) -> &mut Self::Output {
1111         &mut self.0[index.0]
1112     }
1113 }
1114 
1115 /// Indices for use with [`Termios::special_codes`].
1116 pub struct SpecialCodeIndex(usize);
1117 
1118 #[rustfmt::skip]
1119 impl SpecialCodeIndex {
1120     /// `VINTR`
1121     pub const VINTR: Self = Self(c::VINTR as usize);
1122 
1123     /// `VQUIT`
1124     pub const VQUIT: Self = Self(c::VQUIT as usize);
1125 
1126     /// `VERASE`
1127     pub const VERASE: Self = Self(c::VERASE as usize);
1128 
1129     /// `VKILL`
1130     pub const VKILL: Self = Self(c::VKILL as usize);
1131 
1132     /// `VEOF`
1133     pub const VEOF: Self = Self(c::VEOF as usize);
1134 
1135     /// `VTIME`
1136     pub const VTIME: Self = Self(c::VTIME as usize);
1137 
1138     /// `VMIN`
1139     pub const VMIN: Self = Self(c::VMIN as usize);
1140 
1141     /// `VSWTC`
1142     #[cfg(not(any(
1143         bsd,
1144         solarish,
1145         target_os = "aix",
1146         target_os = "haiku",
1147         target_os = "hurd",
1148         target_os = "nto",
1149     )))]
1150     pub const VSWTC: Self = Self(c::VSWTC as usize);
1151 
1152     /// `VSTART`
1153     pub const VSTART: Self = Self(c::VSTART as usize);
1154 
1155     /// `VSTOP`
1156     pub const VSTOP: Self = Self(c::VSTOP as usize);
1157 
1158     /// `VSUSP`
1159     pub const VSUSP: Self = Self(c::VSUSP as usize);
1160 
1161     /// `VEOL`
1162     pub const VEOL: Self = Self(c::VEOL as usize);
1163 
1164     /// `VREPRINT`
1165     #[cfg(not(target_os = "haiku"))]
1166     pub const VREPRINT: Self = Self(c::VREPRINT as usize);
1167 
1168     /// `VDISCARD`
1169     #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1170     pub const VDISCARD: Self = Self(c::VDISCARD as usize);
1171 
1172     /// `VWERASE`
1173     #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1174     pub const VWERASE: Self = Self(c::VWERASE as usize);
1175 
1176     /// `VLNEXT`
1177     #[cfg(not(target_os = "haiku"))]
1178     pub const VLNEXT: Self = Self(c::VLNEXT as usize);
1179 
1180     /// `VEOL2`
1181     pub const VEOL2: Self = Self(c::VEOL2 as usize);
1182 }
1183 
1184 /// `TCSA*` values for use with [`tcsetattr`].
1185 ///
1186 /// [`tcsetattr`]: crate::termios::tcsetattr
1187 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1188 #[repr(u32)]
1189 pub enum OptionalActions {
1190     /// `TCSANOW`—Make the change immediately.
1191     #[doc(alias = "TCSANOW")]
1192     Now = c::TCSANOW as u32,
1193 
1194     /// `TCSADRAIN`—Make the change after all output has been transmitted.
1195     #[doc(alias = "TCSADRAIN")]
1196     Drain = c::TCSADRAIN as u32,
1197 
1198     /// `TCSAFLUSH`—Discard any pending input and then make the change
1199     /// after all output has been transmitted.
1200     #[doc(alias = "TCSAFLUSH")]
1201     Flush = c::TCSAFLUSH as u32,
1202 }
1203 
1204 /// `TC*` values for use with [`tcflush`].
1205 ///
1206 /// [`tcflush`]: crate::termios::tcflush
1207 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1208 #[repr(u32)]
1209 pub enum QueueSelector {
1210     /// `TCIFLUSH`—Flush data received but not read.
1211     #[doc(alias = "TCIFLUSH")]
1212     IFlush = c::TCIFLUSH as u32,
1213 
1214     /// `TCOFLUSH`—Flush data written but not transmitted.
1215     #[doc(alias = "TCOFLUSH")]
1216     OFlush = c::TCOFLUSH as u32,
1217 
1218     /// `TCIOFLUSH`—`IFlush` and `OFlush` combined.
1219     #[doc(alias = "TCIOFLUSH")]
1220     IOFlush = c::TCIOFLUSH as u32,
1221 }
1222 
1223 /// `TC*` values for use with [`tcflow`].
1224 ///
1225 /// [`tcflow`]: crate::termios::tcflow
1226 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1227 #[repr(u32)]
1228 pub enum Action {
1229     /// `TCOOFF`—Suspend output.
1230     #[doc(alias = "TCOOFF")]
1231     OOff = c::TCOOFF as u32,
1232 
1233     /// `TCOON`—Restart suspended output.
1234     #[doc(alias = "TCOON")]
1235     OOn = c::TCOON as u32,
1236 
1237     /// `TCIOFF`—Transmits a STOP byte.
1238     #[doc(alias = "TCIOFF")]
1239     IOff = c::TCIOFF as u32,
1240 
1241     /// `TCION`—Transmits a START byte.
1242     #[doc(alias = "TCION")]
1243     IOn = c::TCION as u32,
1244 }
1245 
1246 /// `struct winsize` for use with [`tcgetwinsize`].
1247 ///
1248 /// [`tcgetwinsize`]: crate::termios::tcgetwinsize
1249 #[doc(alias = "winsize")]
1250 pub type Winsize = c::winsize;
1251 
1252 #[test]
termios_layouts()1253 fn termios_layouts() {
1254     check_renamed_type!(InputModes, tcflag_t);
1255     check_renamed_type!(OutputModes, tcflag_t);
1256     check_renamed_type!(ControlModes, tcflag_t);
1257     check_renamed_type!(LocalModes, tcflag_t);
1258 
1259     // On platforms with a termios/termios2 split, check `termios`.
1260     #[cfg(linux_raw)]
1261     {
1262         check_renamed_type!(Termios, termios2);
1263         check_renamed_struct_renamed_field!(Termios, termios2, input_modes, c_iflag);
1264         check_renamed_struct_renamed_field!(Termios, termios2, output_modes, c_oflag);
1265         check_renamed_struct_renamed_field!(Termios, termios2, control_modes, c_cflag);
1266         check_renamed_struct_renamed_field!(Termios, termios2, local_modes, c_lflag);
1267         check_renamed_struct_renamed_field!(Termios, termios2, line_discipline, c_line);
1268         check_renamed_struct_renamed_field!(Termios, termios2, special_codes, c_cc);
1269         check_renamed_struct_renamed_field!(Termios, termios2, input_speed, c_ispeed);
1270         check_renamed_struct_renamed_field!(Termios, termios2, output_speed, c_ospeed);
1271 
1272         // We assume that `termios` has the same layout as `termios2` minus the
1273         // `c_ispeed` and `c_ospeed` fields.
1274         check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
1275         check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
1276         check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
1277         check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
1278         check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
1279 
1280         // On everything except PowerPC, `termios` matches `termios2` except
1281         // for the addition of `c_ispeed` and `c_ospeed`.
1282         #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
1283         const_assert_eq!(
1284             memoffset::offset_of!(Termios, input_speed),
1285             core::mem::size_of::<c::termios>()
1286         );
1287 
1288         // On PowerPC, `termios2` is `termios`.
1289         #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
1290         assert_eq_size!(c::termios2, c::termios);
1291     }
1292 
1293     #[cfg(not(linux_raw))]
1294     {
1295         // On Mips, Sparc, and Android, the libc lacks the ospeed and ispeed
1296         // fields.
1297         #[cfg(all(
1298             not(all(
1299                 target_env = "gnu",
1300                 any(
1301                     target_arch = "mips",
1302                     target_arch = "mips32r6",
1303                     target_arch = "mips64",
1304                     target_arch = "mips64r6",
1305                     target_arch = "sparc",
1306                     target_arch = "sparc64"
1307                 )
1308             )),
1309             not(all(libc, target_os = "android"))
1310         ))]
1311         check_renamed_type!(Termios, termios);
1312         #[cfg(not(all(
1313             not(all(
1314                 target_env = "gnu",
1315                 any(
1316                     target_arch = "mips",
1317                     target_arch = "mips32r6",
1318                     target_arch = "mips64",
1319                     target_arch = "mips64r6",
1320                     target_arch = "sparc",
1321                     target_arch = "sparc64"
1322                 )
1323             )),
1324             not(all(libc, target_os = "android"))
1325         )))]
1326         const_assert!(core::mem::size_of::<Termios>() >= core::mem::size_of::<c::termios>());
1327 
1328         check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
1329         check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
1330         check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
1331         check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
1332         #[cfg(any(
1333             linux_like,
1334             target_env = "newlib",
1335             target_os = "fuchsia",
1336             target_os = "haiku",
1337             target_os = "redox"
1338         ))]
1339         check_renamed_struct_renamed_field!(Termios, termios, line_discipline, c_line);
1340         check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
1341         #[cfg(not(any(
1342             linux_kernel,
1343             solarish,
1344             target_os = "emscripten",
1345             target_os = "fuchsia"
1346         )))]
1347         {
1348             check_renamed_struct_renamed_field!(Termios, termios, input_speed, c_ispeed);
1349             check_renamed_struct_renamed_field!(Termios, termios, output_speed, c_ospeed);
1350         }
1351         #[cfg(any(target_env = "musl", target_os = "fuchsia"))]
1352         {
1353             check_renamed_struct_renamed_field!(Termios, termios, input_speed, __c_ispeed);
1354             check_renamed_struct_renamed_field!(Termios, termios, output_speed, __c_ospeed);
1355         }
1356     }
1357 
1358     check_renamed_type!(OptionalActions, c_int);
1359     check_renamed_type!(QueueSelector, c_int);
1360     check_renamed_type!(Action, c_int);
1361 }
1362 
1363 #[test]
1364 #[cfg(not(any(
1365     solarish,
1366     target_os = "emscripten",
1367     target_os = "haiku",
1368     target_os = "redox"
1369 )))]
termios_legacy()1370 fn termios_legacy() {
1371     // Check that our doc aliases above are correct.
1372     const_assert_eq!(c::EXTA, c::B19200);
1373     const_assert_eq!(c::EXTB, c::B38400);
1374 }
1375 
1376 #[cfg(bsd)]
1377 #[test]
termios_bsd()1378 fn termios_bsd() {
1379     // On BSD platforms we can assume that the `B*` constants have their
1380     // arbitrary integer speed value. Confirm this.
1381     const_assert_eq!(c::B0, 0);
1382     const_assert_eq!(c::B50, 50);
1383     const_assert_eq!(c::B19200, 19200);
1384     const_assert_eq!(c::B38400, 38400);
1385 }
1386 
1387 #[test]
1388 #[cfg(not(bsd))]
termios_speed_encoding()1389 fn termios_speed_encoding() {
1390     assert_eq!(speed::encode(0), Some(c::B0));
1391     assert_eq!(speed::encode(50), Some(c::B50));
1392     assert_eq!(speed::encode(19200), Some(c::B19200));
1393     assert_eq!(speed::encode(38400), Some(c::B38400));
1394     assert_eq!(speed::encode(1), None);
1395     assert_eq!(speed::encode(!0), None);
1396 
1397     #[cfg(not(linux_kernel))]
1398     {
1399         assert_eq!(speed::decode(c::B0), Some(0));
1400         assert_eq!(speed::decode(c::B50), Some(50));
1401         assert_eq!(speed::decode(c::B19200), Some(19200));
1402         assert_eq!(speed::decode(c::B38400), Some(38400));
1403     }
1404 }
1405 
1406 #[cfg(linux_kernel)]
1407 #[test]
termios_ioctl_contiguity()1408 fn termios_ioctl_contiguity() {
1409     // When using `termios2`, we assume that we can add the optional actions
1410     // value to the ioctl request code. Test this assumption.
1411 
1412     const_assert_eq!(c::TCSETS2, c::TCSETS2 + 0);
1413     const_assert_eq!(c::TCSETSW2, c::TCSETS2 + 1);
1414     const_assert_eq!(c::TCSETSF2, c::TCSETS2 + 2);
1415 
1416     const_assert_eq!(c::TCSANOW - c::TCSANOW, 0);
1417     const_assert_eq!(c::TCSADRAIN - c::TCSANOW, 1);
1418     const_assert_eq!(c::TCSAFLUSH - c::TCSANOW, 2);
1419 
1420     // MIPS is different here.
1421     #[cfg(any(
1422         target_arch = "mips",
1423         target_arch = "mips32r6",
1424         target_arch = "mips64",
1425         target_arch = "mips64r6"
1426     ))]
1427     {
1428         assert_eq!(i128::from(c::TCSANOW) - i128::from(c::TCSETS), 0);
1429         assert_eq!(i128::from(c::TCSADRAIN) - i128::from(c::TCSETS), 1);
1430         assert_eq!(i128::from(c::TCSAFLUSH) - i128::from(c::TCSETS), 2);
1431     }
1432     #[cfg(not(any(
1433         target_arch = "mips",
1434         target_arch = "mips32r6",
1435         target_arch = "mips64",
1436         target_arch = "mips64r6"
1437     )))]
1438     {
1439         const_assert_eq!(c::TCSANOW, 0);
1440         const_assert_eq!(c::TCSADRAIN, 1);
1441         const_assert_eq!(c::TCSAFLUSH, 2);
1442     }
1443 }
1444 
1445 #[cfg(linux_kernel)]
1446 #[test]
termios_cibaud()1447 fn termios_cibaud() {
1448     // Test an assumption.
1449     const_assert_eq!(c::CIBAUD, c::CBAUD << c::IBSHIFT);
1450 }
1451