chlorine/
lib.rs

1#![no_std]
2#![allow(non_camel_case_types)]
3
4//! This just provides the numeric C types, for basic FFI purposes.
5//!
6//! Also, that [`pick!`] macro is nifty.
7
8/// Does all our conditional compilation selection.
9#[macro_export]
10macro_rules! pick {
11  // with a trailing else
12  ($(if #[cfg($($test:meta),*)] {
13      $($if_tokens:tt)*
14    })else+ else {
15      $($else_tokens:tt)*
16    }) => {
17    $crate::pick!{
18      @__forests [ ] ;
19      $( [ {$($test),*} {$($if_tokens)*} ], )*
20      [ { } {$($else_tokens)*} ],
21    }
22  };
23
24  // without a trailing else
25  (if #[cfg($($if_meta:meta),*)] {
26      $($if_tokens:tt)*
27    } $(else if #[cfg($($else_meta:meta),*)] {
28      $($else_tokens:tt)*
29    })*) => {
30    $crate::pick!{
31      @__forests [ ] ;
32      [ {$($if_meta),*} {$($if_tokens)*} ],
33      $( [ {$($else_meta),*} {$($else_tokens)*} ], )*
34    }
35  };
36
37  // private
38  (@__forests [$($not:meta,)*];) => {
39    /* halt expansion */
40  };
41
42  // private
43  (@__forests [$($not:meta,)*]; [{$($m:meta),*} {$($tokens:tt)*}], $($rest:tt)*) => {
44    // This "one weird trick" works because you can't apply a `cfg` to an
45    // expression, only an item or a block, but a macro usage is an item, so
46    // we're configuring the macro usage, which (if configured in) will then
47    // contain a token tree that turns into either an item or an expression.
48    #[cfg(all( $($m,)* not(any($($not),*)) ))]
49    $crate::pick!{ @__identity $($tokens)* }
50
51    $crate::pick!{ @__forests [ $($not,)* $($m,)* ] ; $($rest)* }
52  };
53
54  // private
55  (@__identity $($tokens:tt)*) => {
56    $($tokens)*
57  };
58}
59
60// most of these never change
61
62pub use core::ffi::c_void;
63pub type c_schar = i8;
64pub type c_uchar = u8;
65// char depends on stuff
66pub type c_short = i16;
67pub type c_ushort = u16;
68// int/uint depends on stuff
69// long/ulong depends on stuff
70pub type c_longlong = i64;
71pub type c_ulonglong = u64;
72pub type c_float = f32;
73pub type c_double = f64;
74
75// c_char, c_int, and c_uint are set by the arch
76
77// first we define c_char
78pick! {
79  if #[cfg(any(
80    target_arch = "arm",
81    target_arch = "asmjs",
82    target_arch = "powerpc",
83    target_arch = "powerpc64",
84    target_arch = "s390x",
85    target_arch = "riscv32",
86    target_arch = "riscv64",
87    target_arch = "aarch64",
88    target_arch = "msp430",
89  ))] {
90    // c_char is unsigned (unless using apple)
91    pick! {
92      if #[cfg(any(
93        target_os = "macos",
94        target_os = "ios",
95        target_os = "tvos",
96        target_os = "visionos",
97        target_os = "windows",
98      ))] {
99        pub type c_char = c_schar;
100      } else {
101        pub type c_char = c_uchar;
102      }
103    }
104  } else if #[cfg(any(
105    target_arch = "mips",
106    target_arch = "mips64",
107    target_arch = "sparc64",
108    target_arch = "x86",
109    target_arch = "x86_64",
110    target_arch = "nvptx",
111    target_arch = "nvptx64",
112    target_arch = "xtensa",
113    target_arch = "wasm32",
114    target_arch = "wasm64",
115  ))] {
116    // c_char is signed
117    pub type c_char = c_schar;
118  } else {
119    compile_error!("The alias for c_char, c_int, and c_uint is unknown!");
120  }
121}
122
123// then we define c_int and c_uint
124pick! {
125  if #[cfg(any(
126    target_arch = "arm",
127    target_arch = "asmjs",
128    target_arch = "wasm32",
129    target_arch = "wasm64",
130    target_arch = "powerpc",
131    target_arch = "powerpc64",
132    target_arch = "s390x",
133    target_arch = "riscv32",
134    target_arch = "riscv64",
135    target_arch = "aarch64",
136    target_arch = "mips",
137    target_arch = "mips64",
138    target_arch = "sparc64",
139    target_arch = "x86",
140    target_arch = "x86_64",
141    target_arch = "nvptx",
142    target_arch = "nvptx64",
143    target_arch = "xtensa",
144  ))] {
145    pub type c_int = i32;
146    pub type c_uint = u32;
147  } else if #[cfg(any(
148    target_arch = "msp430",
149  ))] {
150    pub type c_int = i16;
151    pub type c_uint = u16;
152  } else {
153    compile_error!("The alias for c_int and c_uint is unknown!");
154  }
155}
156
157// c_long and c_ulong are set by the OS
158pick! {
159  // in some special cases we ignore pointer size ...
160  if #[cfg(windows)] {
161    pub type c_long = i32;
162    pub type c_ulong = u32;
163  } else if #[cfg(any(
164    target_os = "redox",
165    target_os = "solaris",
166  ))] {
167    pub type c_long = i64;
168    pub type c_ulong = u64;
169  }
170  // but by default we match the size of a long to the size of a pointer
171  else if #[cfg(target_pointer_width = "64")] {
172    pub type c_long = i64;
173    pub type c_ulong = u64;
174  } else if #[cfg(any(
175    target_pointer_width = "16",
176    target_pointer_width = "32",
177  ))] {
178    pub type c_long = i32;
179    pub type c_ulong = u32;
180  } else {
181    compile_error!("The alias for c_long and c_ulong is unknown!");
182  }
183}
184
185// this requires a crate feature is all
186pick! {
187  if #[cfg(feature = "int_extras")] {
188    pub type intmax_t = i64;
189    pub type intptr_t = isize;
190    pub type ptrdiff_t = isize;
191    pub type size_t = usize;
192    pub type ssize_t = isize;
193    pub type uintmax_t = u64;
194    pub type uintptr_t = usize;
195  }
196}