rustix/termios/
types.rs

1use crate::backend::c;
2use crate::{backend, io};
3use 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)]
11pub 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
74impl 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]
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]
95    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]
128    pub fn output_speed(&self) -> u32 {
129        // On Linux and BSDs, `output_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]
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]
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]
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
210impl core::fmt::Debug for Termios {
211    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
234bitflags! {
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
302bitflags! {
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
517bitflags! {
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
581bitflags! {
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.
655pub 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.
814    ///
815    /// On Linux on PowerPC, `TCGETS`/`TCSETS` support the `c_ispeed` and
816    /// `c_ospeed` fields.
817    ///
818    /// On Linux on architectures other than PowerPC, `TCGETS`/`TCSETS` don't
819    /// support the `c_ispeed` and `c_ospeed` fields, so we have to fall back
820    /// to `TCGETS2`/`TCSETS2` to support them.
821    #[cfg(not(any(
822        bsd,
823        all(linux_kernel, any(target_arch = "powerpc", target_arch = "powerpc64"))
824    )))]
825    pub(crate) const fn decode(encoded_speed: c::speed_t) -> Option<u32> {
826        match encoded_speed {
827            c::B0 => Some(0),
828            c::B50 => Some(50),
829            c::B75 => Some(75),
830            c::B110 => Some(110),
831            c::B134 => Some(134),
832            c::B150 => Some(150),
833            c::B200 => Some(200),
834            c::B300 => Some(300),
835            c::B600 => Some(600),
836            c::B1200 => Some(1200),
837            c::B1800 => Some(1800),
838            c::B2400 => Some(2400),
839            c::B4800 => Some(4800),
840            c::B9600 => Some(9600),
841            c::B19200 => Some(19200),
842            c::B38400 => Some(38400),
843            #[cfg(not(target_os = "aix"))]
844            c::B57600 => Some(57600),
845            #[cfg(not(target_os = "aix"))]
846            c::B115200 => Some(115_200),
847            #[cfg(not(any(target_os = "aix", target_os = "nto")))]
848            c::B230400 => Some(230_400),
849            #[cfg(not(any(
850                apple,
851                target_os = "aix",
852                target_os = "dragonfly",
853                target_os = "haiku",
854                target_os = "nto",
855                target_os = "openbsd"
856            )))]
857            c::B460800 => Some(460_800),
858            #[cfg(not(any(
859                bsd,
860                solarish,
861                target_os = "aix",
862                target_os = "haiku",
863                target_os = "nto"
864            )))]
865            c::B500000 => Some(500_000),
866            #[cfg(not(any(
867                bsd,
868                solarish,
869                target_os = "aix",
870                target_os = "haiku",
871                target_os = "nto"
872            )))]
873            c::B576000 => Some(576_000),
874            #[cfg(not(any(
875                apple,
876                target_os = "aix",
877                target_os = "dragonfly",
878                target_os = "haiku",
879                target_os = "nto",
880                target_os = "openbsd"
881            )))]
882            c::B921600 => Some(921_600),
883            #[cfg(not(any(
884                bsd,
885                target_os = "aix",
886                target_os = "haiku",
887                target_os = "nto",
888                target_os = "solaris"
889            )))]
890            c::B1000000 => Some(1_000_000),
891            #[cfg(not(any(
892                bsd,
893                target_os = "aix",
894                target_os = "haiku",
895                target_os = "nto",
896                target_os = "solaris"
897            )))]
898            c::B1152000 => Some(1_152_000),
899            #[cfg(not(any(
900                bsd,
901                target_os = "aix",
902                target_os = "haiku",
903                target_os = "nto",
904                target_os = "solaris"
905            )))]
906            c::B1500000 => Some(1_500_000),
907            #[cfg(not(any(
908                bsd,
909                target_os = "aix",
910                target_os = "haiku",
911                target_os = "nto",
912                target_os = "solaris"
913            )))]
914            c::B2000000 => Some(2_000_000),
915            #[cfg(not(any(
916                target_arch = "sparc",
917                target_arch = "sparc64",
918                bsd,
919                target_os = "aix",
920                target_os = "haiku",
921                target_os = "nto",
922                target_os = "solaris",
923            )))]
924            c::B2500000 => Some(2_500_000),
925            #[cfg(not(any(
926                target_arch = "sparc",
927                target_arch = "sparc64",
928                bsd,
929                target_os = "aix",
930                target_os = "haiku",
931                target_os = "nto",
932                target_os = "solaris",
933            )))]
934            c::B3000000 => Some(3_000_000),
935            #[cfg(not(any(
936                target_arch = "sparc",
937                target_arch = "sparc64",
938                bsd,
939                target_os = "aix",
940                target_os = "haiku",
941                target_os = "nto",
942                target_os = "solaris",
943            )))]
944            c::B3500000 => Some(3_500_000),
945            #[cfg(not(any(
946                target_arch = "sparc",
947                target_arch = "sparc64",
948                bsd,
949                target_os = "aix",
950                target_os = "haiku",
951                target_os = "nto",
952                target_os = "solaris",
953            )))]
954            c::B4000000 => Some(4_000_000),
955            _ => None,
956        }
957    }
958
959    /// Translate from an arbitrary `u32` arbitrary integer speed value to a
960    /// `c::speed_t` code.
961    #[cfg(not(bsd))]
962    pub(crate) const fn encode(speed: u32) -> Option<c::speed_t> {
963        match speed {
964            0 => Some(c::B0),
965            50 => Some(c::B50),
966            75 => Some(c::B75),
967            110 => Some(c::B110),
968            134 => Some(c::B134),
969            150 => Some(c::B150),
970            200 => Some(c::B200),
971            300 => Some(c::B300),
972            600 => Some(c::B600),
973            1200 => Some(c::B1200),
974            1800 => Some(c::B1800),
975            2400 => Some(c::B2400),
976            4800 => Some(c::B4800),
977            9600 => Some(c::B9600),
978            19200 => Some(c::B19200),
979            38400 => Some(c::B38400),
980            #[cfg(not(target_os = "aix"))]
981            57600 => Some(c::B57600),
982            #[cfg(not(target_os = "aix"))]
983            115_200 => Some(c::B115200),
984            #[cfg(not(any(target_os = "aix", target_os = "nto")))]
985            230_400 => Some(c::B230400),
986            #[cfg(not(any(
987                apple,
988                target_os = "aix",
989                target_os = "dragonfly",
990                target_os = "haiku",
991                target_os = "nto",
992                target_os = "openbsd",
993            )))]
994            460_800 => Some(c::B460800),
995            #[cfg(not(any(
996                bsd,
997                solarish,
998                target_os = "aix",
999                target_os = "haiku",
1000                target_os = "nto"
1001            )))]
1002            500_000 => Some(c::B500000),
1003            #[cfg(not(any(
1004                bsd,
1005                solarish,
1006                target_os = "aix",
1007                target_os = "haiku",
1008                target_os = "nto"
1009            )))]
1010            576_000 => Some(c::B576000),
1011            #[cfg(not(any(
1012                apple,
1013                target_os = "aix",
1014                target_os = "dragonfly",
1015                target_os = "haiku",
1016                target_os = "nto",
1017                target_os = "openbsd"
1018            )))]
1019            921_600 => Some(c::B921600),
1020            #[cfg(not(any(
1021                bsd,
1022                target_os = "aix",
1023                target_os = "haiku",
1024                target_os = "nto",
1025                target_os = "solaris"
1026            )))]
1027            1_000_000 => Some(c::B1000000),
1028            #[cfg(not(any(
1029                bsd,
1030                target_os = "aix",
1031                target_os = "haiku",
1032                target_os = "nto",
1033                target_os = "solaris"
1034            )))]
1035            1_152_000 => Some(c::B1152000),
1036            #[cfg(not(any(
1037                bsd,
1038                target_os = "aix",
1039                target_os = "haiku",
1040                target_os = "nto",
1041                target_os = "solaris"
1042            )))]
1043            1_500_000 => Some(c::B1500000),
1044            #[cfg(not(any(
1045                bsd,
1046                target_os = "aix",
1047                target_os = "haiku",
1048                target_os = "nto",
1049                target_os = "solaris"
1050            )))]
1051            2_000_000 => Some(c::B2000000),
1052            #[cfg(not(any(
1053                target_arch = "sparc",
1054                target_arch = "sparc64",
1055                bsd,
1056                target_os = "aix",
1057                target_os = "haiku",
1058                target_os = "nto",
1059                target_os = "solaris",
1060            )))]
1061            2_500_000 => Some(c::B2500000),
1062            #[cfg(not(any(
1063                target_arch = "sparc",
1064                target_arch = "sparc64",
1065                bsd,
1066                target_os = "aix",
1067                target_os = "haiku",
1068                target_os = "nto",
1069                target_os = "solaris",
1070            )))]
1071            3_000_000 => Some(c::B3000000),
1072            #[cfg(not(any(
1073                target_arch = "sparc",
1074                target_arch = "sparc64",
1075                bsd,
1076                target_os = "aix",
1077                target_os = "haiku",
1078                target_os = "nto",
1079                target_os = "solaris",
1080            )))]
1081            3_500_000 => Some(c::B3500000),
1082            #[cfg(not(any(
1083                target_arch = "sparc",
1084                target_arch = "sparc64",
1085                bsd,
1086                target_os = "aix",
1087                target_os = "haiku",
1088                target_os = "nto",
1089                target_os = "solaris",
1090            )))]
1091            4_000_000 => Some(c::B4000000),
1092            _ => None,
1093        }
1094    }
1095}
1096
1097/// An array indexed by [`SpecialCodeIndex`] indicating the current values
1098/// of various special control codes.
1099#[repr(transparent)]
1100#[derive(Clone, Debug)]
1101pub struct SpecialCodes(pub(crate) [c::cc_t; c::NCCS as usize]);
1102
1103impl core::ops::Index<SpecialCodeIndex> for SpecialCodes {
1104    type Output = c::cc_t;
1105
1106    fn index(&self, index: SpecialCodeIndex) -> &Self::Output {
1107        &self.0[index.0]
1108    }
1109}
1110
1111impl core::ops::IndexMut<SpecialCodeIndex> for SpecialCodes {
1112    fn index_mut(&mut self, index: SpecialCodeIndex) -> &mut Self::Output {
1113        &mut self.0[index.0]
1114    }
1115}
1116
1117/// Indices for use with [`Termios::special_codes`].
1118#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1119pub struct SpecialCodeIndex(usize);
1120
1121#[rustfmt::skip]
1122impl SpecialCodeIndex {
1123    /// `VINTR`
1124    pub const VINTR: Self = Self(c::VINTR as usize);
1125
1126    /// `VQUIT`
1127    pub const VQUIT: Self = Self(c::VQUIT as usize);
1128
1129    /// `VERASE`
1130    pub const VERASE: Self = Self(c::VERASE as usize);
1131
1132    /// `VKILL`
1133    pub const VKILL: Self = Self(c::VKILL as usize);
1134
1135    /// `VEOF`
1136    pub const VEOF: Self = Self(c::VEOF as usize);
1137
1138    /// `VTIME`
1139    pub const VTIME: Self = Self(c::VTIME as usize);
1140
1141    /// `VMIN`
1142    pub const VMIN: Self = Self(c::VMIN as usize);
1143
1144    /// `VSWTC`
1145    #[cfg(not(any(
1146        bsd,
1147        solarish,
1148        target_os = "aix",
1149        target_os = "haiku",
1150        target_os = "hurd",
1151        target_os = "nto",
1152    )))]
1153    pub const VSWTC: Self = Self(c::VSWTC as usize);
1154
1155    /// `VSTART`
1156    pub const VSTART: Self = Self(c::VSTART as usize);
1157
1158    /// `VSTOP`
1159    pub const VSTOP: Self = Self(c::VSTOP as usize);
1160
1161    /// `VSUSP`
1162    pub const VSUSP: Self = Self(c::VSUSP as usize);
1163
1164    /// `VEOL`
1165    pub const VEOL: Self = Self(c::VEOL as usize);
1166
1167    /// `VREPRINT`
1168    #[cfg(not(target_os = "haiku"))]
1169    pub const VREPRINT: Self = Self(c::VREPRINT as usize);
1170
1171    /// `VDISCARD`
1172    #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1173    pub const VDISCARD: Self = Self(c::VDISCARD as usize);
1174
1175    /// `VWERASE`
1176    #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1177    pub const VWERASE: Self = Self(c::VWERASE as usize);
1178
1179    /// `VLNEXT`
1180    #[cfg(not(target_os = "haiku"))]
1181    pub const VLNEXT: Self = Self(c::VLNEXT as usize);
1182
1183    /// `VEOL2`
1184    pub const VEOL2: Self = Self(c::VEOL2 as usize);
1185
1186    /// `VSWTCH`
1187    #[cfg(any(solarish, target_os = "haiku", target_os = "nto"))]
1188    pub const VSWTCH: Self = Self(c::VSWTCH as usize);
1189
1190    /// `VDSUSP`
1191    #[cfg(any(bsd, solarish, target_os = "aix", target_os = "hurd", target_os = "nto"))]
1192    pub const VDSUSP: Self = Self(c::VDSUSP as usize);
1193
1194    /// `VSTATUS`
1195    #[cfg(any(bsd, target_os = "hurd", target_os = "illumos"))]
1196    pub const VSTATUS: Self = Self(c::VSTATUS as usize);
1197
1198    /// `VERASE2`
1199    #[cfg(any(freebsdlike, target_os = "illumos"))]
1200    pub const VERASE2: Self = Self(c::VERASE2 as usize);
1201}
1202
1203impl core::fmt::Debug for SpecialCodeIndex {
1204    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1205        match *self {
1206            Self::VINTR => write!(f, "VINTR"),
1207            Self::VQUIT => write!(f, "VQUIT"),
1208            Self::VERASE => write!(f, "VERASE"),
1209            Self::VKILL => write!(f, "VKILL"),
1210            #[cfg(not(any(
1211                solarish,
1212                all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
1213            )))]
1214            Self::VEOF => write!(f, "VEOF"),
1215            #[cfg(not(any(
1216                solarish,
1217                all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
1218            )))]
1219            Self::VTIME => write!(f, "VTIME"),
1220            #[cfg(not(any(
1221                solarish,
1222                all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
1223            )))]
1224            Self::VMIN => write!(f, "VMIN"),
1225
1226            // On Solarish platforms, and Linux on SPARC, `VMIN` and `VTIME`
1227            // have the same value as `VEOF` and `VEOL`.
1228            #[cfg(any(
1229                solarish,
1230                all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
1231            ))]
1232            Self::VMIN => write!(f, "VMIN/VEOF"),
1233            #[cfg(any(
1234                solarish,
1235                all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
1236            ))]
1237            Self::VTIME => write!(f, "VTIME/VEOL"),
1238
1239            #[cfg(not(any(
1240                bsd,
1241                solarish,
1242                target_os = "aix",
1243                target_os = "haiku",
1244                target_os = "hurd",
1245                target_os = "nto",
1246            )))]
1247            Self::VSWTC => write!(f, "VSWTC"),
1248            Self::VSTART => write!(f, "VSTART"),
1249            Self::VSTOP => write!(f, "VSTOP"),
1250            Self::VSUSP => write!(f, "VSUSP"),
1251            #[cfg(not(any(
1252                solarish,
1253                all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
1254            )))]
1255            Self::VEOL => write!(f, "VEOL"),
1256            #[cfg(not(target_os = "haiku"))]
1257            Self::VREPRINT => write!(f, "VREPRINT"),
1258            #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1259            Self::VDISCARD => write!(f, "VDISCARD"),
1260            #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1261            Self::VWERASE => write!(f, "VWERASE"),
1262            #[cfg(not(target_os = "haiku"))]
1263            Self::VLNEXT => write!(f, "VLNEXT"),
1264            Self::VEOL2 => write!(f, "VEOL2"),
1265            #[cfg(any(solarish, target_os = "haiku", target_os = "nto"))]
1266            Self::VSWTCH => write!(f, "VSWTCH"),
1267            #[cfg(any(
1268                bsd,
1269                solarish,
1270                target_os = "aix",
1271                target_os = "hurd",
1272                target_os = "nto"
1273            ))]
1274            Self::VDSUSP => write!(f, "VDSUSP"),
1275            #[cfg(any(bsd, target_os = "hurd", target_os = "illumos"))]
1276            Self::VSTATUS => write!(f, "VSTATUS"),
1277            #[cfg(any(freebsdlike, target_os = "illumos"))]
1278            Self::VERASE2 => write!(f, "VERASE2"),
1279
1280            _ => write!(f, "unknown"),
1281        }
1282    }
1283}
1284
1285/// `TCSA*` values for use with [`tcsetattr`].
1286///
1287/// [`tcsetattr`]: crate::termios::tcsetattr
1288#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1289#[repr(u32)]
1290pub enum OptionalActions {
1291    /// `TCSANOW`—Make the change immediately.
1292    #[doc(alias = "TCSANOW")]
1293    Now = c::TCSANOW as u32,
1294
1295    /// `TCSADRAIN`—Make the change after all output has been transmitted.
1296    #[doc(alias = "TCSADRAIN")]
1297    Drain = c::TCSADRAIN as u32,
1298
1299    /// `TCSAFLUSH`—Discard any pending input and then make the change
1300    /// after all output has been transmitted.
1301    #[doc(alias = "TCSAFLUSH")]
1302    Flush = c::TCSAFLUSH as u32,
1303}
1304
1305/// `TC*` values for use with [`tcflush`].
1306///
1307/// [`tcflush`]: crate::termios::tcflush
1308#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1309#[repr(u32)]
1310pub enum QueueSelector {
1311    /// `TCIFLUSH`—Flush data received but not read.
1312    #[doc(alias = "TCIFLUSH")]
1313    IFlush = c::TCIFLUSH as u32,
1314
1315    /// `TCOFLUSH`—Flush data written but not transmitted.
1316    #[doc(alias = "TCOFLUSH")]
1317    OFlush = c::TCOFLUSH as u32,
1318
1319    /// `TCIOFLUSH`—`IFlush` and `OFlush` combined.
1320    #[doc(alias = "TCIOFLUSH")]
1321    IOFlush = c::TCIOFLUSH as u32,
1322}
1323
1324/// `TC*` values for use with [`tcflow`].
1325///
1326/// [`tcflow`]: crate::termios::tcflow
1327#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1328#[repr(u32)]
1329pub enum Action {
1330    /// `TCOOFF`—Suspend output.
1331    #[doc(alias = "TCOOFF")]
1332    OOff = c::TCOOFF as u32,
1333
1334    /// `TCOON`—Restart suspended output.
1335    #[doc(alias = "TCOON")]
1336    OOn = c::TCOON as u32,
1337
1338    /// `TCIOFF`—Transmits a STOP byte.
1339    #[doc(alias = "TCIOFF")]
1340    IOff = c::TCIOFF as u32,
1341
1342    /// `TCION`—Transmits a START byte.
1343    #[doc(alias = "TCION")]
1344    IOn = c::TCION as u32,
1345}
1346
1347/// `struct winsize` for use with [`tcgetwinsize`].
1348///
1349/// [`tcgetwinsize`]: crate::termios::tcgetwinsize
1350#[doc(alias = "winsize")]
1351pub type Winsize = c::winsize;
1352
1353#[test]
1354fn termios_layouts() {
1355    check_renamed_type!(InputModes, tcflag_t);
1356    check_renamed_type!(OutputModes, tcflag_t);
1357    check_renamed_type!(ControlModes, tcflag_t);
1358    check_renamed_type!(LocalModes, tcflag_t);
1359
1360    // On platforms with a termios/termios2 split, check `termios`.
1361    #[cfg(linux_raw)]
1362    {
1363        check_renamed_type!(Termios, termios2);
1364        check_renamed_struct_renamed_field!(Termios, termios2, input_modes, c_iflag);
1365        check_renamed_struct_renamed_field!(Termios, termios2, output_modes, c_oflag);
1366        check_renamed_struct_renamed_field!(Termios, termios2, control_modes, c_cflag);
1367        check_renamed_struct_renamed_field!(Termios, termios2, local_modes, c_lflag);
1368        check_renamed_struct_renamed_field!(Termios, termios2, line_discipline, c_line);
1369        check_renamed_struct_renamed_field!(Termios, termios2, special_codes, c_cc);
1370        check_renamed_struct_renamed_field!(Termios, termios2, input_speed, c_ispeed);
1371        check_renamed_struct_renamed_field!(Termios, termios2, output_speed, c_ospeed);
1372
1373        // We assume that `termios` has the same layout as `termios2` minus the
1374        // `c_ispeed` and `c_ospeed` fields.
1375        check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
1376        check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
1377        check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
1378        check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
1379        check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
1380
1381        // On everything except PowerPC, `termios` matches `termios2` except
1382        // for the addition of `c_ispeed` and `c_ospeed`.
1383        #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
1384        const_assert_eq!(
1385            memoffset::offset_of!(Termios, input_speed),
1386            core::mem::size_of::<c::termios>()
1387        );
1388
1389        // On PowerPC, `termios2` is `termios`.
1390        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
1391        assert_eq_size!(c::termios2, c::termios);
1392    }
1393
1394    #[cfg(not(linux_raw))]
1395    {
1396        // On MIPS, SPARC, and Android, the libc lacks the ospeed and ispeed
1397        // fields.
1398        #[cfg(all(
1399            not(all(
1400                target_env = "gnu",
1401                any(
1402                    target_arch = "mips",
1403                    target_arch = "mips32r6",
1404                    target_arch = "mips64",
1405                    target_arch = "mips64r6",
1406                    target_arch = "sparc",
1407                    target_arch = "sparc64"
1408                )
1409            )),
1410            not(all(libc, target_os = "android"))
1411        ))]
1412        check_renamed_type!(Termios, termios);
1413        #[cfg(not(all(
1414            not(all(
1415                target_env = "gnu",
1416                any(
1417                    target_arch = "mips",
1418                    target_arch = "mips32r6",
1419                    target_arch = "mips64",
1420                    target_arch = "mips64r6",
1421                    target_arch = "sparc",
1422                    target_arch = "sparc64"
1423                )
1424            )),
1425            not(all(libc, target_os = "android"))
1426        )))]
1427        const_assert!(core::mem::size_of::<Termios>() >= core::mem::size_of::<c::termios>());
1428
1429        check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
1430        check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
1431        check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
1432        check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
1433        #[cfg(any(
1434            linux_like,
1435            target_env = "newlib",
1436            target_os = "fuchsia",
1437            target_os = "haiku",
1438            target_os = "redox"
1439        ))]
1440        check_renamed_struct_renamed_field!(Termios, termios, line_discipline, c_line);
1441        check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
1442        #[cfg(not(any(
1443            linux_kernel,
1444            solarish,
1445            target_os = "emscripten",
1446            target_os = "fuchsia"
1447        )))]
1448        {
1449            check_renamed_struct_renamed_field!(Termios, termios, input_speed, c_ispeed);
1450            check_renamed_struct_renamed_field!(Termios, termios, output_speed, c_ospeed);
1451        }
1452        #[cfg(any(target_env = "musl", target_os = "fuchsia"))]
1453        {
1454            check_renamed_struct_renamed_field!(Termios, termios, input_speed, __c_ispeed);
1455            check_renamed_struct_renamed_field!(Termios, termios, output_speed, __c_ospeed);
1456        }
1457    }
1458
1459    check_renamed_type!(OptionalActions, c_int);
1460    check_renamed_type!(QueueSelector, c_int);
1461    check_renamed_type!(Action, c_int);
1462}
1463
1464#[test]
1465#[cfg(not(any(
1466    solarish,
1467    target_os = "emscripten",
1468    target_os = "haiku",
1469    target_os = "redox"
1470)))]
1471fn termios_legacy() {
1472    // Check that our doc aliases above are correct.
1473    const_assert_eq!(c::EXTA, c::B19200);
1474    const_assert_eq!(c::EXTB, c::B38400);
1475}
1476
1477#[cfg(bsd)]
1478#[test]
1479fn termios_bsd() {
1480    // On BSD platforms we can assume that the `B*` constants have their
1481    // arbitrary integer speed value. Confirm this.
1482    const_assert_eq!(c::B0, 0);
1483    const_assert_eq!(c::B50, 50);
1484    const_assert_eq!(c::B19200, 19200);
1485    const_assert_eq!(c::B38400, 38400);
1486}
1487
1488#[test]
1489#[cfg(not(bsd))]
1490fn termios_speed_encoding() {
1491    assert_eq!(speed::encode(0), Some(c::B0));
1492    assert_eq!(speed::encode(50), Some(c::B50));
1493    assert_eq!(speed::encode(19200), Some(c::B19200));
1494    assert_eq!(speed::encode(38400), Some(c::B38400));
1495    assert_eq!(speed::encode(1), None);
1496    assert_eq!(speed::encode(!0), None);
1497
1498    #[cfg(not(linux_kernel))]
1499    {
1500        assert_eq!(speed::decode(c::B0), Some(0));
1501        assert_eq!(speed::decode(c::B50), Some(50));
1502        assert_eq!(speed::decode(c::B19200), Some(19200));
1503        assert_eq!(speed::decode(c::B38400), Some(38400));
1504    }
1505}
1506
1507#[cfg(linux_kernel)]
1508#[test]
1509fn termios_ioctl_contiguity() {
1510    // When using `termios2`, we assume that we can add the optional actions
1511    // value to the ioctl request code. Test this assumption.
1512
1513    const_assert_eq!(c::TCSETS2, c::TCSETS2 + 0);
1514    const_assert_eq!(c::TCSETSW2, c::TCSETS2 + 1);
1515    const_assert_eq!(c::TCSETSF2, c::TCSETS2 + 2);
1516
1517    const_assert_eq!(c::TCSANOW - c::TCSANOW, 0);
1518    const_assert_eq!(c::TCSADRAIN - c::TCSANOW, 1);
1519    const_assert_eq!(c::TCSAFLUSH - c::TCSANOW, 2);
1520
1521    // MIPS is different here.
1522    #[cfg(any(
1523        target_arch = "mips",
1524        target_arch = "mips32r6",
1525        target_arch = "mips64",
1526        target_arch = "mips64r6"
1527    ))]
1528    {
1529        assert_eq!(i128::from(c::TCSANOW) - i128::from(c::TCSETS), 0);
1530        assert_eq!(i128::from(c::TCSADRAIN) - i128::from(c::TCSETS), 1);
1531        assert_eq!(i128::from(c::TCSAFLUSH) - i128::from(c::TCSETS), 2);
1532    }
1533    #[cfg(not(any(
1534        target_arch = "mips",
1535        target_arch = "mips32r6",
1536        target_arch = "mips64",
1537        target_arch = "mips64r6"
1538    )))]
1539    {
1540        const_assert_eq!(c::TCSANOW, 0);
1541        const_assert_eq!(c::TCSADRAIN, 1);
1542        const_assert_eq!(c::TCSAFLUSH, 2);
1543    }
1544}
1545
1546#[cfg(linux_kernel)]
1547#[test]
1548fn termios_cibaud() {
1549    // Test an assumption.
1550    const_assert_eq!(c::CIBAUD, c::CBAUD << c::IBSHIFT);
1551}