Lower `libc`'s constants through `std/posix`
`inotify-sys` compiles -- 144 lines of content, the seventh of libcosmic's dependencies to go the whole way. `libc::O_NONBLOCK` is the C constant of that name, and Nim's `std/posix` declares the POSIX set under the same names. Both take their values from the platform's headers, so they agree by construction rather than by a table someone would have to maintain -- which is the same argument that makes the `c_type` mapping sound. The import is gated on use: `std/posix` exports a great many names and a crate is entitled to its own `Time` or `Stat`. A constant outside the POSIX set fails at Nim's compile time, by name, rather than silently resolving to something else. `tests/cases/082` checks the values against the real `libc` crate through `//@ extern`, so this is measured against the C headers rather than against a reading of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6e2a88e parent: 95ac909 modified
Cargo.lock +7 -0 | @@ -96,6 +96,12 @@ dependencies = [ | ||
| 96 | 96 | "slab", |
| 97 | 97 | ] |
| 98 | 98 | |
| 99 | +[[package]] | |
| 100 | +name = "libc" | |
| 101 | +version = "0.2.189" | |
| 102 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 103 | +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" | |
| 104 | + | |
| 99 | 105 | [[package]] |
| 100 | 106 | name = "log" |
| 101 | 107 | version = "0.4.34" |
| @@ -138,6 +144,7 @@ version = "0.1.0" | ||
| 138 | 144 | dependencies = [ |
| 139 | 145 | "bitflags", |
| 140 | 146 | "futures", |
| 147 | + "libc", | |
| 141 | 148 | "log", |
| 142 | 149 | "proc-macro2", |
| 143 | 150 | "quote", |
| @@ -96,6 +96,12 @@ dependencies = [ | |||
| 96 | "slab", | 96 | "slab", |
| 97 | ] | 97 | ] |
| 98 | 98 | ||
| 99 | +[[package]] | ||
| 100 | +name = "libc" | ||
| 101 | +version = "0.2.189" | ||
| 102 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 103 | +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" | ||
| 104 | + | ||
| 99 | [[package]] | 105 | [[package]] |
| 100 | name = "log" | 106 | name = "log" |
| 101 | version = "0.4.34" | 107 | version = "0.4.34" |
| @@ -138,6 +144,7 @@ version = "0.1.0" | |||
| 138 | dependencies = [ | 144 | dependencies = [ |
| 139 | "bitflags", | 145 | "bitflags", |
| 140 | "futures", | 146 | "futures", |
| 147 | + "libc", | ||
| 141 | "log", | 148 | "log", |
| 142 | "proc-macro2", | 149 | "proc-macro2", |
| 143 | "quote", | 150 | "quote", |
modified
Cargo.toml +1 -0 | @@ -15,3 +15,4 @@ syn = { version = "3.0.5", features = ["full", "extra-traits", "visit", "visit-m | ||
| 15 | 15 | bitflags = "2" |
| 16 | 16 | log = "0.4" |
| 17 | 17 | futures = "0.3" |
| 18 | +libc = "0.2" | |
| @@ -15,3 +15,4 @@ syn = { version = "3.0.5", features = ["full", "extra-traits", "visit", "visit-m | |||
| 15 | bitflags = "2" | 15 | bitflags = "2" |
| 16 | log = "0.4" | 16 | log = "0.4" |
| 17 | futures = "0.3" | 17 | futures = "0.3" |
| 18 | +libc = "0.2" | ||
modified
src/lower.rs +16 -0 | @@ -361,6 +361,8 @@ pub struct Lowerer { | ||
| 361 | 361 | /// before the prelude is written. |
| 362 | 362 | uses_sync: std::cell::Cell<bool>, |
| 363 | 363 | uses_i128: std::cell::Cell<bool>, |
| 364 | + /// Whether a `libc::` constant was named, which pulls in `std/posix`. | |
| 365 | + uses_posix: std::cell::Cell<bool>, | |
| 364 | 366 | /// Function-local `struct`/`enum` declarations, by name and by the source |
| 365 | 367 | /// text of the declaration. Nim has no function-local type namespace, so |
| 366 | 368 | /// these land in the module's one namespace; two different types under one |
| @@ -532,6 +534,7 @@ impl Lowerer { | ||
| 532 | 534 | uses_async: false, |
| 533 | 535 | uses_sync: std::cell::Cell::new(false), |
| 534 | 536 | uses_i128: std::cell::Cell::new(false), |
| 537 | + uses_posix: std::cell::Cell::new(false), | |
| 535 | 538 | local_items: HashMap::new(), |
| 536 | 539 | emitted_local: std::collections::HashSet::new(), |
| 537 | 540 | emitted_assoc: std::collections::HashSet::new(), |
| @@ -933,6 +936,9 @@ impl Lowerer { | ||
| 933 | 936 | if self.uses_i128.get() { |
| 934 | 937 | out.push_str(include_str!("prelude_i128.nim")); |
| 935 | 938 | } |
| 939 | + if self.uses_posix.get() { | |
| 940 | + out.push_str(include_str!("prelude_posix.nim")); | |
| 941 | + } | |
| 936 | 942 | if self.uses_sync.get() { |
| 937 | 943 | out.push_str(include_str!("prelude_sync.nim")); |
| 938 | 944 | out.push('\n'); |
| @@ -6378,6 +6384,16 @@ impl Lowerer { | ||
| 6378 | 6384 | } |
| 6379 | 6385 | } |
| 6380 | 6386 | |
| 6387 | + // `libc::O_NONBLOCK` is the C constant of that name, which | |
| 6388 | + // `std/posix` declares under the same name and takes from the | |
| 6389 | + // same header. See `src/prelude_posix.nim`. | |
| 6390 | + if let Some(q) = p.path.segments.iter().rev().nth(1) { | |
| 6391 | + if q.ident == "libc" && name.chars().all(|c| c.is_ascii_uppercase() || c == '_' || c.is_ascii_digit()) { | |
| 6392 | + self.uses_posix.set(true); | |
| 6393 | + return Ok(Val::new(ident(&name), Some(Nim::Prim("cint".into())))); | |
| 6394 | + } | |
| 6395 | + } | |
| 6396 | + | |
| 6381 | 6397 | // `Self::CONST` where `Self` is a type parameter: which |
| 6382 | 6398 | // constant that is depends on the instantiation, so it is read |
| 6383 | 6399 | // through the accessor rather than named. |
| @@ -361,6 +361,8 @@ pub struct Lowerer { | |||
| 361 | /// before the prelude is written. | 361 | /// before the prelude is written. |
| 362 | uses_sync: std::cell::Cell<bool>, | 362 | uses_sync: std::cell::Cell<bool>, |
| 363 | uses_i128: std::cell::Cell<bool>, | 363 | uses_i128: std::cell::Cell<bool>, |
| 364 | + /// Whether a `libc::` constant was named, which pulls in `std/posix`. | ||
| 365 | + uses_posix: std::cell::Cell<bool>, | ||
| 364 | /// Function-local `struct`/`enum` declarations, by name and by the source | 366 | /// Function-local `struct`/`enum` declarations, by name and by the source |
| 365 | /// text of the declaration. Nim has no function-local type namespace, so | 367 | /// text of the declaration. Nim has no function-local type namespace, so |
| 366 | /// these land in the module's one namespace; two different types under one | 368 | /// these land in the module's one namespace; two different types under one |
| @@ -532,6 +534,7 @@ impl Lowerer { | |||
| 532 | uses_async: false, | 534 | uses_async: false, |
| 533 | uses_sync: std::cell::Cell::new(false), | 535 | uses_sync: std::cell::Cell::new(false), |
| 534 | uses_i128: std::cell::Cell::new(false), | 536 | uses_i128: std::cell::Cell::new(false), |
| 537 | + uses_posix: std::cell::Cell::new(false), | ||
| 535 | local_items: HashMap::new(), | 538 | local_items: HashMap::new(), |
| 536 | emitted_local: std::collections::HashSet::new(), | 539 | emitted_local: std::collections::HashSet::new(), |
| 537 | emitted_assoc: std::collections::HashSet::new(), | 540 | emitted_assoc: std::collections::HashSet::new(), |
| @@ -933,6 +936,9 @@ impl Lowerer { | |||
| 933 | if self.uses_i128.get() { | 936 | if self.uses_i128.get() { |
| 934 | out.push_str(include_str!("prelude_i128.nim")); | 937 | out.push_str(include_str!("prelude_i128.nim")); |
| 935 | } | 938 | } |
| 939 | + if self.uses_posix.get() { | ||
| 940 | + out.push_str(include_str!("prelude_posix.nim")); | ||
| 941 | + } | ||
| 936 | if self.uses_sync.get() { | 942 | if self.uses_sync.get() { |
| 937 | out.push_str(include_str!("prelude_sync.nim")); | 943 | out.push_str(include_str!("prelude_sync.nim")); |
| 938 | out.push('\n'); | 944 | out.push('\n'); |
| @@ -6378,6 +6384,16 @@ impl Lowerer { | |||
| 6378 | } | 6384 | } |
| 6379 | } | 6385 | } |
| 6380 | 6386 | ||
| 6387 | + // `libc::O_NONBLOCK` is the C constant of that name, which | ||
| 6388 | + // `std/posix` declares under the same name and takes from the | ||
| 6389 | + // same header. See `src/prelude_posix.nim`. | ||
| 6390 | + if let Some(q) = p.path.segments.iter().rev().nth(1) { | ||
| 6391 | + if q.ident == "libc" && name.chars().all(|c| c.is_ascii_uppercase() || c == '_' || c.is_ascii_digit()) { | ||
| 6392 | + self.uses_posix.set(true); | ||
| 6393 | + return Ok(Val::new(ident(&name), Some(Nim::Prim("cint".into())))); | ||
| 6394 | + } | ||
| 6395 | + } | ||
| 6396 | + | ||
| 6381 | // `Self::CONST` where `Self` is a type parameter: which | 6397 | // `Self::CONST` where `Self` is a type parameter: which |
| 6382 | // constant that is depends on the instantiation, so it is read | 6398 | // constant that is depends on the instantiation, so it is read |
| 6383 | // through the accessor rather than named. | 6399 | // through the accessor rather than named. |
added
src/prelude_posix.nim +14 -0 | new file mode 100644 | ||
| @@ -0,0 +1,14 @@ | ||
| 1 | + | |
| 2 | +# --------------------------------------------------------------------------- | |
| 3 | +# `libc`'s constants. | |
| 4 | +# | |
| 5 | +# `libc::O_NONBLOCK` is the C constant of that name, and `std/posix` declares | |
| 6 | +# the POSIX set under the same names with the same values -- both take them | |
| 7 | +# from the platform's headers, so they are equal by construction rather than | |
| 8 | +# by a table someone maintained. | |
| 9 | +# | |
| 10 | +# Imported only when a translated file names one, because `std/posix` exports | |
| 11 | +# a great many names and a crate is entitled to its own `Time` or `Stat`. | |
| 12 | +# A constant outside the POSIX set fails at Nim's compile time, by name. | |
| 13 | +# --------------------------------------------------------------------------- | |
| 14 | +import std/posix | |
| new file mode 100644 | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | + | ||
| 2 | +# --------------------------------------------------------------------------- | ||
| 3 | +# `libc`'s constants. | ||
| 4 | +# | ||
| 5 | +# `libc::O_NONBLOCK` is the C constant of that name, and `std/posix` declares | ||
| 6 | +# the POSIX set under the same names with the same values -- both take them | ||
| 7 | +# from the platform's headers, so they are equal by construction rather than | ||
| 8 | +# by a table someone maintained. | ||
| 9 | +# | ||
| 10 | +# Imported only when a translated file names one, because `std/posix` exports | ||
| 11 | +# a great many names and a crate is entitled to its own `Time` or `Stat`. | ||
| 12 | +# A constant outside the POSIX set fails at Nim's compile time, by name. | ||
| 13 | +# --------------------------------------------------------------------------- | ||
| 14 | +import std/posix | ||
added
tests/cases/082-libc-consts.rs +17 -0 | new file mode 100644 | ||
| @@ -0,0 +1,17 @@ | ||
| 1 | +//@ extern: libc | |
| 2 | +// `libc::O_NONBLOCK` is the C constant of that name, and Nim's `std/posix` | |
| 3 | +// declares the POSIX set under the same names — both take them from the | |
| 4 | +// platform's headers, so they agree by construction rather than by a table. | |
| 5 | +fn main() { | |
| 6 | + println!("{}", libc::O_NONBLOCK); | |
| 7 | + println!("{}", libc::O_CLOEXEC); | |
| 8 | + println!("{}", libc::EAGAIN); | |
| 9 | + println!("{}", libc::EINVAL); | |
| 10 | + println!("{}", libc::SOCK_STREAM); | |
| 11 | + println!("{}", libc::AF_UNIX); | |
| 12 | + | |
| 13 | + // Combined the way flags actually get used. | |
| 14 | + let flags = libc::O_NONBLOCK | libc::O_CLOEXEC; | |
| 15 | + println!("{}", flags); | |
| 16 | + println!("{}", flags & libc::O_CLOEXEC != 0); | |
| 17 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | +//@ extern: libc | ||
| 2 | +// `libc::O_NONBLOCK` is the C constant of that name, and Nim's `std/posix` | ||
| 3 | +// declares the POSIX set under the same names — both take them from the | ||
| 4 | +// platform's headers, so they agree by construction rather than by a table. | ||
| 5 | +fn main() { | ||
| 6 | + println!("{}", libc::O_NONBLOCK); | ||
| 7 | + println!("{}", libc::O_CLOEXEC); | ||
| 8 | + println!("{}", libc::EAGAIN); | ||
| 9 | + println!("{}", libc::EINVAL); | ||
| 10 | + println!("{}", libc::SOCK_STREAM); | ||
| 11 | + println!("{}", libc::AF_UNIX); | ||
| 12 | + | ||
| 13 | + // Combined the way flags actually get used. | ||
| 14 | + let flags = libc::O_NONBLOCK | libc::O_CLOEXEC; | ||
| 15 | + println!("{}", flags); | ||
| 16 | + println!("{}", flags & libc::O_CLOEXEC != 0); | ||
| 17 | +} | ||