Skip to content

Commit

Permalink
Make #[repr(C)] optional
Browse files Browse the repository at this point in the history
You can either use `std::os::raw::c_int` or `libc::c_int`.

Unfortunately, the feature name is awkward to work around
dtolnay/trybuild#171.
  • Loading branch information
kupiakos committed Sep 10, 2022
1 parent e8fdaf1 commit c7eee97
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 7 deletions.
7 changes: 5 additions & 2 deletions Cargo.toml
Expand Up @@ -11,6 +11,10 @@ keywords = ["enum", "open", "integer", "newtype"]
include = ["/src", "/LICENSE", "Cargo.toml"]

[features]
# This is not named libc because it would require "dep:libc"
# which doesn't work with trybuild: https://github.com/dtolnay/trybuild/issues/171.
libc_ = ["libc", "open-enum-derive/repr_c"]
std = ["open-enum-derive/repr_c"]

# Needed to test #[deny(missing_docs)], which doesn't trigger in unit or integration tests.
[[bin]]
Expand All @@ -19,8 +23,7 @@ path = "src/test-lints.rs"

[dependencies]
open-enum-derive = { path = "derive", version = "0.2.0" }
# TODO: consider making this optional - I tried and trybuild started failing
libc = { version = "0.2" }
libc = { version = "0.2", optional = true }

[dev-dependencies]
trybuild = "1"
Expand Down
3 changes: 2 additions & 1 deletion derive/Cargo.toml
Expand Up @@ -13,9 +13,10 @@ include = ["/src", "../LICENSE", "Cargo.toml"]
proc-macro = true

[features]
# Enable #[repr(C)] open enums
repr_c = []

[dependencies]
syn = { version = "1", features = ["full"] }
quote = "1"
proc-macro2 = "1.0.43"
libc = { version = "0.2" }
11 changes: 11 additions & 0 deletions derive/src/lib.rs
Expand Up @@ -113,6 +113,7 @@ enum Repr {
I64,
Usize,
Isize,
#[cfg(feature = "repr_c")]
C,
}

Expand Down Expand Up @@ -157,6 +158,7 @@ impl Repr {
Repr::I64 => "i64",
Repr::Usize => "usize",
Repr::Isize => "isize",
#[cfg(feature = "repr_c")]
Repr::C => "C",
}
}
Expand All @@ -167,6 +169,7 @@ impl ToTokens for Repr {
tokens.extend([match self {
// Technically speaking, #[repr(C)] on an enum isn't always `c_int`,
// but those who care can fix it if they need.
#[cfg(feature = "repr_c")]
Repr::C => quote!(::open_enum::__private::c_int),
x => x.name().parse::<TokenStream>().unwrap(),
}])
Expand All @@ -187,7 +190,15 @@ impl Parse for Repr {
"u64" => Repr::U64,
"usize" => Repr::Usize,
"isize" => Repr::Isize,
#[cfg(feature = "repr_c")]
"C" => Repr::C,
#[cfg(not(feature = "repr_c"))]
"C" => {
return Err(Error::new(
ident.span(),
"#[repr(C)] requires either the `std` or `libc_` feature",
))
}
_ => {
return Err(Error::new(
ident.span(),
Expand Down
7 changes: 7 additions & 0 deletions src/lib.rs
Expand Up @@ -199,5 +199,12 @@ pub use open_enum_derive::open_enum;
/// Utility items only to be used by macros. Do not expect API stability.
#[doc(hidden)]
pub mod __private {
#[cfg(all(feature = "libc", not(feature = "std")))]
pub use libc::c_int;

#[cfg(feature = "std")]
extern crate std;

#[cfg(feature = "std")]
pub use std::os::raw::c_int;
}
12 changes: 8 additions & 4 deletions tests/basic.rs
Expand Up @@ -59,7 +59,6 @@ enum Color {
Azure,
}


#[test]
fn values() {
assert_eq!(Fruit::Apple.0, 0);
Expand Down Expand Up @@ -114,19 +113,24 @@ fn other_derive() {
HasHash(20).hash(&mut hasher);
}

#[cfg(any(feature = "libc", feature = "std"))]
#[test]
fn repr_c() {
use core::mem::size_of;

#[repr(C)]
#[open_enum]
enum AnimalSound {
Moo, Honk, Bahhh,
Moo,
Honk,
Bahhh,
}
use libc::c_int;

assert_eq!(AnimalSound::Moo.0, 0);
assert_eq!(size_of::<AnimalSound>(), size_of::<c_int>());
assert_eq!(
size_of::<AnimalSound>(),
size_of::<open_enum::__private::c_int>()
);
}

#[test]
Expand Down

0 comments on commit c7eee97

Please sign in to comment.