diff --git a/.github/workflows/cbindgen.yml b/.github/workflows/cbindgen.yml index f2614e9b3..bf2791329 100644 --- a/.github/workflows/cbindgen.yml +++ b/.github/workflows/cbindgen.yml @@ -71,6 +71,11 @@ jobs: python -m pip install --upgrade pip wheel pip install Cython==0.29.* + - name: Install Zig + uses: goto-bus-stop/setup-zig@v1 + with: + version: master + - name: Build run: | cargo build --verbose diff --git a/docs.md b/docs.md index 9a434aa06..e24ca0c1f 100644 --- a/docs.md +++ b/docs.md @@ -37,8 +37,8 @@ cbindgen --config cbindgen.toml --crate my_rust_library --output my_header.h ``` This produces a header file for C++. For C, add the `--lang c` switch. \ -`cbindgen` also supports generation of [Cython](https://cython.org) bindings, -use `--lang cython` for that. +`cbindgen` also supports generation of [Cython](https://cython.org) and [Zig](https://ziglang.org) bindings, +use `--lang cython` or `--lang zig` for that. See `cbindgen --help` for more options. @@ -385,7 +385,7 @@ Note that many options defined here only apply for one of C or C++. Usually it's ```toml # The language to output bindings in # -# possible values: "C", "C++", "Cython" +# possible values: "C", "C++", "Cython", "Zig" # # default: "C++" language = "C" diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index 2b0f86a9a..576f112ff 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -146,7 +146,7 @@ impl Bindings { write!(out, "#define {}", f); out.new_line(); } - if self.config.pragma_once && self.config.language != Language::Cython { + if self.config.pragma_once && self.config.language != Language::Cython && self.config.language != Language::Zig { out.new_line_if_not_start(); write!(out, "#pragma once"); out.new_line(); @@ -233,6 +233,10 @@ impl Bindings { out.new_line(); out.close_brace(false); } + Language::Zig => { + out.write("const std = @import(\"std\");"); + out.new_line(); + } } } @@ -253,6 +257,13 @@ impl Bindings { } } + if self.config.language == Language::Zig { + for (module, names) in &self.config.zig.cimports { + write!(out, "const {} = @cImport ({{ @cInclude(\"{}\")}});", names.join(""), module); + out.new_line(); + } + } + if let Some(ref line) = self.config.after_includes { write!(out, "{}", line); out.new_line(); @@ -325,6 +336,16 @@ impl Bindings { } } + if self.config.language == Language::Zig { + if let Some(ref using_namespaces) = self.config.using_namespaces { + for namespace in using_namespaces { + out.new_line(); + write!(out, "usingnamespace {};", namespace); + } + out.new_line(); + } + } + if self.config.language == Language::Cxx || self.config.cpp_compatible_c() { out.new_line(); out.write("extern \"C\" {"); diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 1018e09d8..8f8a3f0a2 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -106,7 +106,9 @@ impl CDecl { "error generating cdecl for {:?}", t ); - self.type_qualifers = "const".to_owned(); + if config.language != Language::Zig { + self.type_qualifers = "const".to_owned(); + } } assert!( @@ -130,7 +132,9 @@ impl CDecl { "error generating cdecl for {:?}", t ); - self.type_qualifers = "const".to_owned(); + if config.language != Language::Zig { + self.type_qualifers = "const".to_owned(); + } } assert!( @@ -138,7 +142,12 @@ impl CDecl { "error generating cdecl for {:?}", t ); - self.type_name = p.to_repr_c(config).to_string(); + + if config.language == Language::Zig { + self.type_name = p.to_repr_zig().to_string(); + } else { + self.type_name = p.to_repr_c(config).to_string(); + } } Type::Ptr { ref ty, @@ -190,7 +199,9 @@ impl CDecl { } } - write!(out, "{}", self.type_name); + if config.language != Language::Zig { + write!(out, "{}", self.type_name); + } if !self.type_generic_args.is_empty() { out.write("<"); @@ -200,11 +211,16 @@ impl CDecl { // When we have an identifier, put a space between the type and the declarators if ident.is_some() { - out.write(" "); + if config.language == Language::Zig && self.declarators.is_empty() { + out.write(""); + } else { + out.write(" "); + } } // Write the left part of declarators before the identifier let mut iter_rev = self.declarators.iter().rev().peekable(); + let mut is_functors = false; #[allow(clippy::while_let_on_iterator)] while let Some(declarator) = iter_rev.next() { @@ -216,9 +232,23 @@ impl CDecl { is_nullable, is_ref, } => { - out.write(if is_ref { "&" } else { "*" }); + if config.language != Language::Zig { + out.write(if is_ref { "&" } else { "*" }); + } else { + if !self.type_qualifers.is_empty() { + write!(out, "{}", self.type_qualifers); + } else { + if config.language != Language::Zig { + out.write("_"); + } + } + } if is_const { - out.write("const "); + if config.language == Language::Zig { + write!(out, "{} ", config.style.zig_def()); + } else { + out.write("const "); + } } if !is_nullable && !is_ref && config.language != Language::Cython { if let Some(attr) = &config.pointer.non_null_attribute { @@ -232,16 +262,25 @@ impl CDecl { } } CDeclarator::Func(..) => { - if next_is_pointer { + if next_is_pointer && config.language != Language::Zig { out.write("("); } + is_functors = true; } } } // Write the identifier if let Some(ident) = ident { - write!(out, "{}", ident); + if config.language == Language::Zig && self.declarators.is_empty() { + if ident.is_empty() { + write!(out, "{}", self.type_name); + } else { + write!(out, "{}: {}", ident, self.type_name); + } + } else { + write!(out, "{}", ident); + } } // Write the right part of declarators after the identifier @@ -253,19 +292,46 @@ impl CDecl { match *declarator { CDeclarator::Ptr { .. } => { last_was_pointer = true; + + if config.language == Language::Zig { + if self.type_name.contains("u8") + || self.type_name.contains("const u8") + || self.type_name.contains("CStr") + || self.type_name.contains("c_char") + { + write!(out, ": ?[*:0]{}", self.type_name); + } else if is_functors { + out.write(": ?fn"); + } else { + write!(out, ": ?*{}", self.type_name); + } + } } CDeclarator::Array(ref constant) => { if last_was_pointer { out.write(")"); } - write!(out, "[{}]", constant); + if config.language == Language::Zig { + if constant.is_empty() { + write!(out, "{}: [*]{}", self.type_qualifers, self.type_name); + } else { + write!( + out, + "{}: [{}]{}", + self.type_qualifers, constant, self.type_name + ); + } + } else { + write!(out, "[{}]", constant); + } last_was_pointer = false; } CDeclarator::Func(ref args, layout_vertical) => { - if last_was_pointer { + if last_was_pointer && config.language != Language::Zig { out.write(")"); } + is_functors = true; out.write("("); if args.is_empty() && config.language == Language::C { @@ -300,6 +366,10 @@ impl CDecl { } out.write(")"); + if config.language == Language::Zig { + write!(out, " {}", self.type_name); + } + last_was_pointer = true; } } diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index b4a0cb789..d758e9577 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -23,6 +23,7 @@ pub enum Language { Cxx, C, Cython, + Zig, } impl FromStr for Language { @@ -42,6 +43,8 @@ impl FromStr for Language { "C" => Ok(Language::C), "cython" => Ok(Language::Cython), "Cython" => Ok(Language::Cython), + "zig" => Ok(Language::Zig), + "Zig" => Ok(Language::Zig), _ => Err(format!("Unrecognized Language: '{}'.", s)), } } @@ -54,6 +57,7 @@ impl Language { match self { Language::Cxx | Language::C => "typedef", Language::Cython => "ctypedef", + Language::Zig => "pub const", } } } @@ -243,6 +247,14 @@ impl Style { "ctypedef " } } + + pub fn zig_def(self) -> &'static str { + if self.generate_tag() { + "pub const " + } else { + "pub extern" + } + } } impl Default for Style { @@ -698,6 +710,8 @@ pub struct ConstantConfig { pub allow_static_const: bool, /// Whether a generated constant should be constexpr in C++ mode. pub allow_constexpr: bool, + /// Whether a generated compile-time should be comptime in Zig mode. + pub allow_comptime: bool, /// Sort key for constants pub sort_by: Option, } @@ -707,6 +721,7 @@ impl Default for ConstantConfig { ConstantConfig { allow_static_const: true, allow_constexpr: true, + allow_comptime: true, sort_by: None, } } @@ -881,6 +896,15 @@ pub struct CythonConfig { pub cimports: BTreeMap>, } +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(rename_all = "snake_case")] +#[serde(deny_unknown_fields)] +#[serde(default)] +pub struct ZigConfig { + pub header: Option, + pub cimports: BTreeMap>, +} + /// A collection of settings to customize the generated bindings. #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] @@ -1003,6 +1027,8 @@ pub struct Config { pub only_target_dependencies: bool, /// Configuration options specific to Cython. pub cython: CythonConfig, + /// Configuration options specific to Zig. + pub zig: ZigConfig, } impl Default for Config { @@ -1045,6 +1071,7 @@ impl Default for Config { pointer: PtrConfig::default(), only_target_dependencies: false, cython: CythonConfig::default(), + zig: ZigConfig::default(), } } } @@ -1055,7 +1082,7 @@ impl Config { } pub(crate) fn include_guard(&self) -> Option<&str> { - if self.language == Language::Cython { + if self.language == Language::Cython || self.language == Language::Zig { None } else { self.include_guard.as_deref() @@ -1063,7 +1090,7 @@ impl Config { } pub(crate) fn includes(&self) -> &[String] { - if self.language == Language::Cython { + if self.language == Language::Cython || self.language == Language::Zig { &[] } else { &self.includes @@ -1071,7 +1098,7 @@ impl Config { } pub(crate) fn sys_includes(&self) -> &[String] { - if self.language == Language::Cython { + if self.language == Language::Cython || self.language == Language::Zig { &[] } else { &self.sys_includes diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index d1cbcba8f..2d7bd34c6 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -475,7 +475,7 @@ impl Literal { return write!(out, "{}", known); } let path_separator = match config.language { - Language::Cython | Language::C => "_", + Language::Cython | Language::Zig | Language::C => "_", Language::Cxx => { if config.structure.associated_constants_in_body { "::" @@ -534,6 +534,7 @@ impl Literal { Language::C => write!(out, "({})", export_name), Language::Cxx => write!(out, "{}", export_name), Language::Cython => write!(out, "<{}>", export_name), + Language::Zig => write!(out, ":{} = ", export_name), } write!(out, "{{ "); @@ -551,6 +552,7 @@ impl Literal { Language::Cxx => write!(out, "/* .{} = */ ", ordered_key), Language::C => write!(out, ".{} = ", ordered_key), Language::Cython => {} + Language::Zig => write!(out, ".{} = ", ordered_key), } lit.write(config, out); } @@ -759,6 +761,7 @@ impl Constant { self.documentation.write(config, out); let allow_constexpr = config.constant.allow_constexpr && self.value.can_be_constexpr(); + let allow_comptime = config.constant.allow_comptime; match config.language { Language::Cxx if config.constant.allow_static_const || allow_constexpr => { if allow_constexpr { @@ -792,6 +795,18 @@ impl Constant { write!(out, " {} # = ", name); value.write(config, out); } + Language::Zig if allow_comptime => { + if allow_comptime { + out.write("comptime "); + } + } + Language::Zig => { + out.write(config.style.zig_def()); + self.ty.write(config, out); + write!(out, "{} = ", name); + value.write(config, out); + write!(out, ";"); + } } condition.write_after(config, out); diff --git a/src/bindgen/ir/documentation.rs b/src/bindgen/ir/documentation.rs index 6822c0eaf..2cfcac3f0 100644 --- a/src/bindgen/ir/documentation.rs +++ b/src/bindgen/ir/documentation.rs @@ -57,6 +57,14 @@ impl Source for Documentation { return; } + if config.language == Language::Zig { + for line in &self.doc_comment[..end] { + write!(out, "///{}", line); + out.new_line(); + } + return; + } + let style = match config.documentation_style { DocumentationStyle::Auto if config.language == Language::C => DocumentationStyle::Doxy, DocumentationStyle::Auto if config.language == Language::Cxx => DocumentationStyle::Cxx, diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 6409a7913..1db4fdc18 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -656,7 +656,11 @@ impl Item for Enum { impl Source for Enum { fn write(&self, config: &Config, out: &mut SourceWriter) { - let size = self.repr.ty.map(|ty| ty.to_primitive().to_repr_c(config)); + let size = if config.language == Language::Zig { + self.repr.ty.map(|ty| ty.to_primitive().to_repr_zig()) + } else { + self.repr.ty.map(|ty| ty.to_primitive().to_repr_c(config)) + }; let has_data = self.tag.is_some(); let inline_tag_field = Self::inline_tag_field(&self.repr); let tag_name = self.tag_name(); @@ -801,6 +805,9 @@ impl Enum { write!(out, "{}enum {}", config.style.cython_def(), tag_name); } } + Language::Zig => { + write!(out, "{}{} = enum", config.style.zig_def(), tag_name); + } } out.open_brace(); @@ -829,7 +836,7 @@ impl Enum { out.write("#ifndef __cplusplus"); } - if config.language != Language::Cxx { + if config.language != Language::Cxx && config.language != Language::Zig { out.new_line(); write!(out, "{} {} {};", config.language.typedef(), prim, tag_name); } @@ -855,6 +862,9 @@ impl Enum { Language::C if config.style.generate_typedef() => out.write("typedef "), Language::C | Language::Cxx => {} Language::Cython => out.write(config.style.cython_def()), + Language::Zig => { + write!(out, "{}{} = extern ", config.style.zig_def(), self.export_name()); + } } out.write(if inline_tag_field { "union" } else { "struct" }); @@ -865,7 +875,7 @@ impl Enum { } } - if config.language != Language::C || config.style.generate_tag() { + if config.language != Language::C && config.language != Language::Zig { write!(out, " {}", self.export_name()); } @@ -927,7 +937,11 @@ impl Enum { out.write("enum "); } - write!(out, "{} tag;", tag_name); + if config.language != Language::Zig { + write!(out, "{} tag;", tag_name); + }else { + write!(out, "tag: {},", tag_name); + } if wrap_tag { out.close_brace(true); @@ -974,10 +988,14 @@ impl Enum { if config.language != Language::Cython { out.close_brace(true); } + } else if config.language == Language::Zig { + write!(out, "{}: {},", name, body.export_name()); } else if config.style.generate_typedef() || config.language == Language::Cython { write!(out, "{} {};", body.export_name(), name); } else { - write!(out, "struct {} {};", body.export_name(), name); + if config.language != Language::Zig { + write!(out, "struct {} {};", body.export_name(), name); + } } if config.language != Language::Cython { condition.write_after(config, out); diff --git a/src/bindgen/ir/field.rs b/src/bindgen/ir/field.rs index 6e132bfaf..d7a8826f0 100644 --- a/src/bindgen/ir/field.rs +++ b/src/bindgen/ir/field.rs @@ -28,6 +28,16 @@ impl Field { } } + pub fn from_type(ty: Type) -> Field { + Field { + name: "".to_string(), + ty, + cfg: None, + annotations: AnnotationSet::new(), + documentation: Documentation::none(), + } + } + pub fn load(field: &syn::Field, self_path: &Path) -> Result, String> { Ok(if let Some(mut ty) = Type::load(&field.ty)? { ty.replace_self_with(self_path); @@ -61,13 +71,13 @@ impl Source for Field { cdecl::write_field(out, &self.ty, &self.name, config); // Cython extern declarations don't manage layouts, layouts are defined entierly by the // corresponding C code. So we can omit bitfield sizes which are not supported by Cython. - if config.language != Language::Cython { + if config.language != Language::Cython || config.language != Language::Zig { if let Some(bitfield) = self.annotations.atom("bitfield") { write!(out, ": {}", bitfield.unwrap_or_default()); } } - if config.language != Language::Cython { + if config.language != Language::Cython || config.language != Language::Zig { condition.write_after(config, out); // FIXME(#634): `write_vertical_source_list` should support // configuring list elements natively. For now we print a newline diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 840e3d391..fa4ae73ca 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -247,14 +247,21 @@ impl Source for Function { func.documentation.write(config, out); if func.extern_decl { - out.write("extern "); - } else { - if let Some(ref prefix) = prefix { - write!(out, "{} ", prefix); + out.write("pub extern "); + if config.language == Language::Zig { + out.write("fn"); } - if func.annotations.must_use(config) { - if let Some(ref anno) = config.function.must_use { - write!(out, "{} ", anno); + } else { + if config.language == Language::Zig { + out.write("pub extern fn"); + } else { + if let Some(ref prefix) = prefix { + write!(out, "{} ", prefix); + } + if func.annotations.must_use(config) { + if let Some(ref anno) = config.function.must_use { + write!(out, "{} ", anno); + } } } } @@ -294,16 +301,21 @@ impl Source for Function { func.documentation.write(config, out); if func.extern_decl { - out.write("extern "); - } else { - if let Some(ref prefix) = prefix { - write!(out, "{}", prefix); - out.new_line(); + out.write("pub extern "); + if config.language == Language::Zig { + out.write("fn"); } - if func.annotations.must_use(config) { - if let Some(ref anno) = config.function.must_use { - write!(out, "{}", anno); - out.new_line(); + } else { + if config.language == Language::Zig { + out.write("pub extern fn"); + } else { + if let Some(ref prefix) = prefix { + write!(out, "{} ", prefix); + } + if func.annotations.must_use(config) { + if let Some(ref anno) = config.function.must_use { + write!(out, "{} ", anno); + } } } } diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 4451d4a16..3140a99e1 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -169,6 +169,11 @@ impl Source for OpaqueItem { out.write("pass"); out.close_brace(false); } + Language::Zig => { + write!(out,"const {} = opaque", self.export_name()); + out.open_brace(); + out.close_brace(true); + } } condition.write_after(config, out); diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index be199739d..e1ceb73a5 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -416,12 +416,13 @@ impl Source for Struct { Language::C if config.style.generate_typedef() => out.write("typedef "), Language::C | Language::Cxx => {} Language::Cython => out.write(config.style.cython_def()), + Language::Zig => out.write(config.style.zig_def()), } // Cython extern declarations don't manage layouts, layouts are defined entierly by the // corresponding C code. So this `packed` is only for documentation, and missing // `aligned(n)` is also not a problem. - if config.language == Language::Cython { + if config.language == Language::Cython || config.language == Language::Zig { if let Some(align) = self.alignment { match align { ReprAlign::Packed => out.write("packed "), @@ -430,7 +431,11 @@ impl Source for Struct { } } - out.write("struct"); + if config.language == Language::Zig { + write!(out, "{} = extern struct", self.export_name()); + } else { + out.write("struct"); + } if config.language != Language::Cython { if let Some(align) = self.alignment { @@ -455,7 +460,7 @@ impl Source for Struct { } } - if config.language != Language::C || config.style.generate_tag() { + if config.language != Language::Zig && config.language != Language::C { write!(out, " {}", self.export_name()); } @@ -467,7 +472,7 @@ impl Source for Struct { out.new_line(); } - out.write_vertical_source_list(&self.fields, ListType::Cap(";")); + out.write_vertical_source_list(&self.fields, ListType::Cap(if config.language != Language::Zig {";"}else{","})); if config.language == Language::Cython && self.fields.is_empty() { out.write("pass"); } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index cd52fec72..acfb8ceb6 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -194,6 +194,106 @@ impl PrimitiveType { } } + pub fn to_repr_zig(&self) -> &'static str { + match *self { + PrimitiveType::Bool => "bool", + PrimitiveType::Void => "anyopaque", + PrimitiveType::Char => "u8", + PrimitiveType::SChar => "i8", + PrimitiveType::UChar => "u8", + PrimitiveType::Char32 => "u32", + PrimitiveType::Integer { + kind, + signed, + zeroable: _, + } => match kind { + IntKind::Short => { + if signed { + "c_short" + } else { + "c_ushort" + } + } + IntKind::Int => { + if signed { + "c_int" + } else { + "c_uint" + } + } + IntKind::Long => { + if signed { + "c_long" + } else { + "c_ulong" + } + } + IntKind::LongLong => { + if signed { + "c_longlong" + } else { + "c_ulonglong" + } + } + IntKind::SizeT => { + if signed { + "ssize_t" + } else { + "size_t" + } + } + IntKind::Size => { + if signed { + "isize" + } else { + "usize" + } + } + IntKind::B8 => { + if signed { + "i8" + } else { + "u8" + } + } + IntKind::B16 => { + if signed { + "i16" + } else { + "u16" + } + } + IntKind::B32 => { + if signed { + "i32" + } else { + "u32" + } + } + IntKind::B64 => { + if signed { + "i64" + } else { + "u64" + } + } + }, + PrimitiveType::Float => "f32", + PrimitiveType::Double => "f64", + PrimitiveType::PtrDiffT => "ptrdiff_t", + PrimitiveType::VaList => { + #[cfg(target_os = "windows")] + { + "va_list" + } + #[cfg(not(target_os = "windows"))] + { + "..." + } + } + } + } + pub fn to_repr_c(&self, config: &Config) -> &'static str { match *self { PrimitiveType::Void => "void", diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 626732e2a..a7a31c67e 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -199,6 +199,10 @@ impl Source for Typedef { Field::from_name_and_type(self.export_name().to_owned(), self.aliased.clone()) .write(config, out); } + Language::Zig => { + write!(out, "{}{} = ", config.style.zig_def(), self.export_name()); + Field::from_type(self.aliased.clone()).write(config, out); + } } out.write(";"); diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 07bd16c58..e1888093f 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -279,6 +279,7 @@ impl Source for Union { Language::C if config.style.generate_typedef() => out.write("typedef "), Language::C | Language::Cxx => {} Language::Cython => out.write(config.style.cython_def()), + Language::Zig => out.write(config.style.zig_def()), } out.write("union"); diff --git a/src/bindgen/writer.rs b/src/bindgen/writer.rs index 3291af911..ecfc5de6d 100644 --- a/src/bindgen/writer.rs +++ b/src/bindgen/writer.rs @@ -154,7 +154,7 @@ impl<'a, F: Write> SourceWriter<'a, F> { pub fn open_brace(&mut self) { match self.bindings.config.language { - Language::Cxx | Language::C => match self.bindings.config.braces { + Language::Cxx | Language::C | Language::Zig => match self.bindings.config.braces { Braces::SameLine => { self.write(" {"); self.push_tab(); @@ -178,7 +178,7 @@ impl<'a, F: Write> SourceWriter<'a, F> { pub fn close_brace(&mut self, semicolon: bool) { self.pop_tab(); match self.bindings.config.language { - Language::Cxx | Language::C => { + Language::Cxx | Language::C | Language::Zig => { self.new_line(); if semicolon { self.write("};"); diff --git a/src/main.rs b/src/main.rs index 0004cf70e..35489c1c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -157,7 +157,7 @@ fn main() { .long("lang") .value_name("LANGUAGE") .help("Specify the language to output bindings in") - .possible_values(&["c++", "C++", "c", "C", "cython", "Cython"]), + .possible_values(&["c++", "C++", "c", "C", "cython", "Cython", "zig", "Zig"]), ) .arg( Arg::new("cpp-compat") diff --git a/tests/expectations/alias.zig b/tests/expectations/alias.zig new file mode 100644 index 000000000..ec8586f1f --- /dev/null +++ b/tests/expectations/alias.zig @@ -0,0 +1,31 @@ +const std = @import("std"); + +pub const Status = enum(c_int) { + Ok = 0, + Err = -1, +}; + +pub const Dep = extern struct { + a: i32, + b: f32, +}; + +pub const Foo_i32 = extern struct { + a: i32, + b: i32, + c: Dep, +}; + +pub const IntFoo = Foo_i32; + +pub const Foo_f64 = extern struct { + a: f64, + b: f64, + c: Dep, +}; + +pub const DoubleFoo = Foo_f64; +pub const Unit = i32; +pub const SpecialStatus = Status; + +extern fn root(x: IntFoo, y: DoubleFoo, z: Unit, w: SpecialStatus) anyopaque; diff --git a/tests/expectations/annotation.zig b/tests/expectations/annotation.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/annotation.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/array.zig b/tests/expectations/array.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/array.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/asserted_cast.zig b/tests/expectations/asserted_cast.zig new file mode 100644 index 000000000..f3db0c9de --- /dev/null +++ b/tests/expectations/asserted_cast.zig @@ -0,0 +1 @@ +const std = @import("std"); \ No newline at end of file diff --git a/tests/expectations/assoc_const_conflict.zig b/tests/expectations/assoc_const_conflict.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/assoc_const_conflict.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/bitfield.zig b/tests/expectations/bitfield.zig new file mode 100644 index 000000000..773348024 --- /dev/null +++ b/tests/expectations/bitfield.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const HasBitfields = packed struct { + foo: u8, + bar: u56, +}; + +extern fn root(?*const HasBitfields) anyopaque; diff --git a/tests/expectations/bitflags.zig b/tests/expectations/bitflags.zig new file mode 100644 index 000000000..5b5676341 --- /dev/null +++ b/tests/expectations/bitflags.zig @@ -0,0 +1,35 @@ +const std = @import("std"); + +pub const AlignFlags = extern struct { + bits: u8, +}; + +pub const DebugFlags = extern struct { + bits: u32, +}; + +extern fn root(flags: AlignFlags, bigger_flags: DebugFlags) void; + +pub const AlignFlags_AUTO = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 0)), +}); + +pub const AlignFlags_NORMAL = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1)), +}); + +pub const AlignFlags_START = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1) << @as(c_int, 1)), +}); + +pub const AlignFlags_END = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1) << @as(c_int, 2)), +}); + +pub const AlignFlags_FLEX_START = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1) << @as(c_int, 3)), +}); + +pub const DebugFlags_BIGGEST_ALLOWED = std.mem.zeroInit(DebugFlags, .{ + .bits = std.zig.c_translation.cast(u32, @as(c_int, 1) << @as(c_int, 31)), +}); diff --git a/tests/expectations/body.zig b/tests/expectations/body.zig new file mode 100644 index 000000000..0dd0a2cc2 --- /dev/null +++ b/tests/expectations/body.zig @@ -0,0 +1,75 @@ +const std = @import("std"); + +pub const MyCLikeEnum = extern union(c_uint) { + Foo1, + Bar1, + Baz1, +}; + +pub const MyCLikeEnum_Prepended = extern union(c_uint) { + Foo1_Prepended, + Bar1_Prepended, + Baz1_Prepended, +}; + +pub const MyFancyStruct = extern struct { + i: i32, +}; + +pub const MyFancyEnum_Tag = extern union(c_uint) { + Foo, + Bar, + Baz, +}; + +const struct_unnamed_2 = extern struct { + bar: i32, +}; +const struct_unnamed_3 = extern struct { + baz: i32, +}; +const union_unnamed_1 = extern union { + unnamed_0: struct_unnamed_2, + unnamed_1: struct_unnamed_3, +}; +pub const MyFancyEnum = extern struct { + tag: MyFancyEnum_Tag, + unnamed_0: union_unnamed_1, +}; +pub const MyUnion = extern union { + f: f32, + u: u32, + extra_member: i32, +}; +pub const MyFancyStruct_Prepended = extern struct { + i: i32, +}; + +pub const MyFancyEnum_Prepended_Tag = extern union(c_uint) { + Foo_Prepended, + Bar_Prepended, + Baz_Prepended, +}; + +const struct_unnamed_5 = extern struct { + bar_prepended: i32, +}; +const struct_unnamed_6 = extern struct { + baz_prepended: i32, +}; +const union_unnamed_4 = extern union { + unnamed_0: struct_unnamed_5, + unnamed_1: struct_unnamed_6, +}; +pub const MyFancyEnum_Prepended = extern struct { + tag: MyFancyEnum_Prepended_Tag, + unnamed_0: union_unnamed_4, +}; + +pub const MyUnion_Prepended = extern union { + extra_member: i32, + f: f32, + u: u32, +}; + +extern fn root(s: MyFancyStruct, e: MyFancyEnum, c: MyCLikeEnum, u: MyUnion, sp: MyFancyStruct_Prepended, ep: MyFancyEnum_Prepended, cp: MyCLikeEnum_Prepended, up: MyUnion_Prepended) anyopaque; diff --git a/tests/expectations/box.zig b/tests/expectations/box.zig new file mode 100644 index 000000000..90f4f06cb --- /dev/null +++ b/tests/expectations/box.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +pub const struct_NotReprC_____i32 = opaque {}; +pub const NotReprC_____i32 = struct_NotReprC_____i32; +pub const Foo = NotReprC_____i32; +pub const MyStruct = extern struct { + number: [*c]i32, +}; +extern fn root(a: ?*const Foo, with_box: [*c]const MyStruct) anyopaque; +extern fn drop_box(x: [*c]i32) anyopaque; +extern fn drop_box_opt(x: [*c]i32) anyopaque; diff --git a/tests/expectations/cdecl.zig b/tests/expectations/cdecl.zig new file mode 100644 index 000000000..14fe62d67 --- /dev/null +++ b/tests/expectations/cdecl.zig @@ -0,0 +1,22 @@ +const std = @import("std"); + +pub const A = ?fn () callconv(.C) void; +pub const B = ?fn () callconv(.C) void; +pub const C = ?fn (i32, i32) callconv(.C) bool; +pub const D = ?fn (i32) callconv(.C) ?fn (f32) callconv(.C) bool; +pub const E = ?fn () callconv(.C) [*c]const [16]i32; +pub const F = [*c]const i32; +pub const G = [*c]const [*c]const i32; +pub const H = [*c]const [*c]i32; +pub const I = [*c]const [16]i32; +pub const J = [*c]?fn (f32) callconv(.C) f64; +pub const K = [16]i32; +pub const L = [16][*c]const i32; +pub const M = [16]?fn (i32, i32) callconv(.C) bool; +pub const N = [16]?fn (i32, i32) callconv(.C) void; + +pub const P = ?fn (i32, bool, bool, i32) callconv(.C) void; + +extern fn O() ?fn () callconv(.C) void; + +extern fn root(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: [*c]i32, l: [*c][*c]const i32, m: [*c]?fn (i32, i32) callconv(.C) bool, n: [*c]?fn (i32, i32) callconv(.C) void, p: P) void; diff --git a/tests/expectations/cell.zig b/tests/expectations/cell.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/cell.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/cfg.zig b/tests/expectations/cfg.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/cfg.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/char.zig b/tests/expectations/char.zig new file mode 100644 index 000000000..cddd27b90 --- /dev/null +++ b/tests/expectations/char.zig @@ -0,0 +1,6 @@ +const std = @import("std"); + +pub const Foo = extern struct { + a: u32, +}; +extern fn root(a: Foo) anyopaque; diff --git a/tests/expectations/constant.zig b/tests/expectations/constant.zig new file mode 100644 index 000000000..a18511539 --- /dev/null +++ b/tests/expectations/constant.zig @@ -0,0 +1,9 @@ +const std = @import("std"); + +pub const FOO: u32 = 10; + +pub const Foo = extern struct { + x: [FOO]i32, +}; + +extern fn root(x: Foo) anyopaque; diff --git a/tests/expectations/constant_big.zig b/tests/expectations/constant_big.zig new file mode 100644 index 000000000..b656ec5d3 --- /dev/null +++ b/tests/expectations/constant_big.zig @@ -0,0 +1,9 @@ +const std = @import("std"); + +const UNSIGNED_NEEDS_ULL_SUFFIX: c_ulonglong = 9223372036854775808; + +const UNSIGNED_DOESNT_NEED_ULL_SUFFIX: c_ulonglong = 8070450532247928832; + +const SIGNED_NEEDS_ULL_SUFFIX: c_longlong = -9223372036854775808; + +const SIGNED_DOESNT_NEED_ULL_SUFFIX : c_longlong = -9223372036854775807; \ No newline at end of file diff --git a/tests/expectations/cython_options.zig b/tests/expectations/cython_options.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/cython_options.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/dep_v2.zig b/tests/expectations/dep_v2.zig new file mode 100644 index 000000000..e458840ff --- /dev/null +++ b/tests/expectations/dep_v2.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const dep_struct = extern struct { + x: u32, + y: f64, +}; + +extern fn get_x(dep_struct: ?*const dep_struct) c_int; diff --git a/tests/expectations/derive_eq.zig b/tests/expectations/derive_eq.zig new file mode 100644 index 000000000..9e398dd92 --- /dev/null +++ b/tests/expectations/derive_eq.zig @@ -0,0 +1,39 @@ +const std = @import("std"); + +pub const Foo = extern struct { + a: bool, + b: i32, +}; + +pub const Bar_Tag = enum { + Baz, + Bazz, + FooNamed, + FooParen, +}; + +pub const Bazz_Body = extern struct { + tag: Bar_Tag, + named: Foo, +}; + +pub const FooNamed_Body = extern struct { + tag: Bar_Tag, + different: i32, + fields: u32, +}; + +pub const FooParen_Body = extern struct { + tag: Bar_Tag, + _0: i32, + _1: Foo, +}; + +pub const Bar = extern union { + tag: Bar_Tag, + bazz: Bazz_Body, + foo_named: FooNamed_Body, + foo_paren: FooParen_Body, +}; + +extern fn root(bar: Bar) Foo; diff --git a/tests/expectations/display_list.zig b/tests/expectations/display_list.zig new file mode 100644 index 000000000..a98128020 --- /dev/null +++ b/tests/expectations/display_list.zig @@ -0,0 +1,38 @@ +const std = @import("std"); + +pub const Rect = extern struct { + x: f32, + y: f32, + w: f32, + h: f32, +}; +pub const Color = extern struct { + r: u8, + g: u8, + b: u8, + a: u8, +}; + +pub const DisplayItem_Tag = enum(c_int) { + Fill, + Image, + ClearScreen, +}; + +pub const Fill_Body = extern struct { + tag: DisplayItem_Tag, + _0: Rect, + _1: Color, +}; +pub const Image_Body = extern struct { + tag: DisplayItem_Tag, + id: u32, + bounds: Rect, +}; +pub const DisplayItem = extern union { + tag: DisplayItem_Tag, + fill: Fill_Body, + image: Image_Body, +}; + +extern fn push_item(item: DisplayItem) bool; diff --git a/tests/expectations/doclength_short.zig b/tests/expectations/doclength_short.zig new file mode 100644 index 000000000..e5f799e73 --- /dev/null +++ b/tests/expectations/doclength_short.zig @@ -0,0 +1,14 @@ +const std = @import("std"); + +// The root of all evil. +// +// But at least it contains some more documentation as someone would expect +// from a simple test case like this. Though, this shouldn't appear in the +// output. +extern fn root() anyopaque; + +// A little above the root, and a lot more visible, with a run-on sentence +// to test going over the first line. +// +// Still not here, though. +extern fn trunk() anyopaque; diff --git a/tests/expectations/docstyle.c99.zig b/tests/expectations/docstyle.c99.zig new file mode 100644 index 000000000..ca42cf937 --- /dev/null +++ b/tests/expectations/docstyle.c99.zig @@ -0,0 +1,4 @@ +const std = @import("std"); + +// The root of all evil. +extern fn root() anyopaque; diff --git a/tests/expectations/docstyle_auto.zig b/tests/expectations/docstyle_auto.zig new file mode 100644 index 000000000..ca42cf937 --- /dev/null +++ b/tests/expectations/docstyle_auto.zig @@ -0,0 +1,4 @@ +const std = @import("std"); + +// The root of all evil. +extern fn root() anyopaque; diff --git a/tests/expectations/documentation.zig b/tests/expectations/documentation.zig new file mode 100644 index 000000000..67ef12342 --- /dev/null +++ b/tests/expectations/documentation.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +// The root of all evil. +// +// But at least it contains some more documentation as someone would expect +// from a simple test case like this. +// +// # Hint +// +// Always ensure that everything is properly documented, even if you feel lazy. +// **Sometimes** it is also helpful to include some markdown formatting. +// +// //////////////////////////////////////////////////////////////////////////// +// +// Attention: +// +// Rust is going to trim all leading `/` symbols. If you want to use them as a +// marker you need to add at least a single whitespace inbetween the tripple +// slash doc-comment marker and the rest. +// +extern fn root() anyopaque; diff --git a/tests/expectations/enum.zig b/tests/expectations/enum.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/enum.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/enum_self.zig b/tests/expectations/enum_self.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/enum_self.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/euclid.zig b/tests/expectations/euclid.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/euclid.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/exclude_generic_monomorph.zig b/tests/expectations/exclude_generic_monomorph.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/exclude_generic_monomorph.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/expand.zig b/tests/expectations/expand.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/expand.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/export_name.zig b/tests/expectations/export_name.zig new file mode 100644 index 000000000..fbb98c225 --- /dev/null +++ b/tests/expectations/export_name.zig @@ -0,0 +1,3 @@ +const std = @import("std"); + +extern fn do_the_thing_with_export_name() anyopaque; diff --git a/tests/expectations/extern.zig b/tests/expectations/extern.zig new file mode 100644 index 000000000..07da36837 --- /dev/null +++ b/tests/expectations/extern.zig @@ -0,0 +1,10 @@ +const std = @import("std"); + +pub const Normal = extern struct { + x: i32, + y: f32, +}; + +extern fn foo() i32; + +extern fn bar(a: Normal) anyopaque; diff --git a/tests/expectations/extern_2.zig b/tests/expectations/extern_2.zig new file mode 100644 index 000000000..017e415e3 --- /dev/null +++ b/tests/expectations/extern_2.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +extern fn first() anyopaque; + +extern fn second() anyopaque; diff --git a/tests/expectations/external_workspace_child.zig b/tests/expectations/external_workspace_child.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/external_workspace_child.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/fns.tag.zig b/tests/expectations/fns.tag.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/fns.tag.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/fns.zig b/tests/expectations/fns.zig new file mode 100644 index 000000000..c06f8fde9 --- /dev/null +++ b/tests/expectations/fns.zig @@ -0,0 +1,13 @@ +const std = @import("std"); + +pub const Fns = extern struct { + _noArgs: ?fn() anyopaque, + _anonymousArg: ?fn() anyopaque, + _returnsNumber: ?fn() i32, + _namedArgs: ?fn(first: i32, snd: i16) i8, + _namedArgsWildcards: ?fn(_: i32, named: i16, _1: i64) i8, +}; + +extern fn root(_fns: Fns) anyopaque; + +extern fn no_return() anyopaque; diff --git a/tests/expectations/forward_declaration.zig b/tests/expectations/forward_declaration.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/forward_declaration.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/function_args.zig b/tests/expectations/function_args.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/function_args.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/function_noreturn.zig b/tests/expectations/function_noreturn.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/function_noreturn.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/generic_pointer.zig b/tests/expectations/generic_pointer.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/generic_pointer.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/global_attr.zig b/tests/expectations/global_attr.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/global_attr.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/ignore.zig b/tests/expectations/ignore.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/ignore.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/include.zig b/tests/expectations/include.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/include.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/include_guard.zig b/tests/expectations/include_guard.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/include_guard.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/include_item.zig b/tests/expectations/include_item.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/include_item.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/infinite_recursion_typedef_monomorph.zig b/tests/expectations/infinite_recursion_typedef_monomorph.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/infinite_recursion_typedef_monomorph.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/inner_mod.zig b/tests/expectations/inner_mod.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/inner_mod.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/item_types.zig b/tests/expectations/item_types.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/item_types.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/layout.zig b/tests/expectations/layout.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/layout.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/layout_aligned_opaque.zig b/tests/expectations/layout_aligned_opaque.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/layout_aligned_opaque.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/layout_packed_opaque.zig b/tests/expectations/layout_packed_opaque.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/layout_packed_opaque.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/lifetime_arg.zig b/tests/expectations/lifetime_arg.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/lifetime_arg.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/linestyle_cr.zig b/tests/expectations/linestyle_cr.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/linestyle_cr.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/linestyle_if.zig b/tests/expectations/linestyle_if.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/linestyle_if.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/literal_target.zig b/tests/expectations/literal_target.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/literal_target.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/mangle.zig b/tests/expectations/mangle.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/mangle.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/manuallydrop.zig b/tests/expectations/manuallydrop.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/manuallydrop.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/maybeuninit.zig b/tests/expectations/maybeuninit.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/maybeuninit.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/mod_2015.zig b/tests/expectations/mod_2015.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/mod_2015.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/mod_2018.zig b/tests/expectations/mod_2018.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/mod_2018.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/monomorph_2.zig b/tests/expectations/monomorph_2.zig new file mode 100644 index 000000000..587190cc8 --- /dev/null +++ b/tests/expectations/monomorph_2.zig @@ -0,0 +1,19 @@ +const std = @import("std"); + +const A = opaque {}; + +const B = opaque {}; + +pub const List_A = extern struct { + _members: ?*A, + count: usize, +}; + +pub const List_B = extern struct { + _members: ?*B, + count: usize, +}; + +extern fn foo(a: List_A) anyopaque; + +extern fn bar(b: List_B) anyopaque; diff --git a/tests/expectations/must_use.zig b/tests/expectations/must_use.zig new file mode 100644 index 000000000..1e954ddf5 --- /dev/null +++ b/tests/expectations/must_use.zig @@ -0,0 +1,10 @@ +const std = @import("std"); + +pub const MaybeOwnedPtr_i32_Tag = enum { + Owned_i32, + None_i32, +}; + +pub const MaybeOwnedPtr_i32 = extern struct { + tag: MaybeOwnedPtr_i32_Tag, +}; \ No newline at end of file diff --git a/tests/expectations/nested_import.zig b/tests/expectations/nested_import.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/nested_import.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/no_includes.zig b/tests/expectations/no_includes.zig new file mode 100644 index 000000000..69bb11bab --- /dev/null +++ b/tests/expectations/no_includes.zig @@ -0,0 +1 @@ +extern fn root() anyopaque; diff --git a/tests/expectations/nonnull.zig b/tests/expectations/nonnull.zig new file mode 100644 index 000000000..ca190d57c --- /dev/null +++ b/tests/expectations/nonnull.zig @@ -0,0 +1,17 @@ +const std = @import("std"); + +const Opaque = opaque {}; + +pub const Foo_u64 = extern struct { + _a: ?*f32, + _b: ?*u64, + _c: ?*Opaque, + __d: ?*u64, + __e: ?*f32, + __f: ?*Opaque, + _g: ?*u64, + _h: ?*i32, + __i: ?*i32, +}; + +extern fn root(_arg: ?*i32, _foo: ?*Foo_u64, __d: ?*Opaque) anyopaque; diff --git a/tests/expectations/nonzero.zig b/tests/expectations/nonzero.zig new file mode 100644 index 000000000..dee33e26f --- /dev/null +++ b/tests/expectations/nonzero.zig @@ -0,0 +1,18 @@ +const std = @import("std"); + +const Option_i64 = opaque {}; + +pub const NonZeroTest = extern struct { + a: u8, + b: u16, + c: u32, + d: u64, + e: i8, + f: i16, + g: i32, + h: i64, + i: i64, + j: ?*const Option_i64, +}; + +extern fn root(_test: NonZeroTest, a: u8, b: u16, c: u32, d: u64, e: i8, f: i16, g: i32, h: i64, i: i64, j: ?*const Option_i64) anyopaque; diff --git a/tests/expectations/opaque.zig b/tests/expectations/opaque.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/opaque.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/pin.zig b/tests/expectations/pin.zig new file mode 100644 index 000000000..7e0594944 --- /dev/null +++ b/tests/expectations/pin.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const PinTest = extern struct { + _pinned_box: ?*i32, + _pinned_ref: ?*i32, +}; + +extern fn root(_s: ?*i32, p: PinTest) anyopaque; diff --git a/tests/expectations/pragma_once.zig b/tests/expectations/pragma_once.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/pragma_once.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/prefix.zig b/tests/expectations/prefix.zig new file mode 100644 index 000000000..bc19218c2 --- /dev/null +++ b/tests/expectations/prefix.zig @@ -0,0 +1,23 @@ +const std = @import("std"); + +pub const LEN = 22; + +pub const X = (22 << 22); + +pub const Y = (X + X); + +pub const NamedLenArray = [LEN]i32; + +pub const ValuedLenArray = [22]i32; + +pub const AbsoluteFontWeight_Tag = enum { + Weight, + Normal, + Bold, +}; + +pub const AbsoluteFontWeight = extern union { + tag: AbsoluteFontWeight_Tag, + weight_tag: AbsoluteFontWeight_Tag, + weight: f32, +}; diff --git a/tests/expectations/prefixed_struct_literal_deep.zig b/tests/expectations/prefixed_struct_literal_deep.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/prefixed_struct_literal_deep.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/ptrs_as_arrays.zig b/tests/expectations/ptrs_as_arrays.zig new file mode 100644 index 000000000..af351be15 --- /dev/null +++ b/tests/expectations/ptrs_as_arrays.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +extern fn ptr_as_array(n: u32, arg: [3]u32, _v: ?*u64) anyopaque; + +extern fn ptr_as_array1(n: u32, arg: [3]u32, v: [4]u64) anyopaque; + +extern fn ptr_as_array2(n: u32, arg: [*]u32, v: [*]u64) anyopaque; + +extern fn ptr_as_array_wrong_syntax(_arg: ?*u32, _v: ?*u32, _: ?*u32) anyopaque; + +extern fn ptr_as_array_unnamed(_: ?*u32, _: ?*u32) anyopaque; diff --git a/tests/expectations/raw_ident.zig b/tests/expectations/raw_ident.zig new file mode 100644 index 000000000..334089796 --- /dev/null +++ b/tests/expectations/raw_ident.zig @@ -0,0 +1,14 @@ +const std = @import("std"); + +pub const Enum = enum(c_int) { + a, + b, +}; + +pub const Struct = extern struct { + field: Enum, +}; + +pub const STATIC = Enum; + +extern fn (arg: Struct) anyopaque; diff --git a/tests/expectations/raw_lines.zig b/tests/expectations/raw_lines.zig new file mode 100644 index 000000000..643bb5513 --- /dev/null +++ b/tests/expectations/raw_lines.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub const VERSION = 1; + +extern fn root() anyopaque; diff --git a/tests/expectations/rename.zig b/tests/expectations/rename.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/rename.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/rename_crates.zig b/tests/expectations/rename_crates.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/rename_crates.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/renaming_overrides_prefixing.zig b/tests/expectations/renaming_overrides_prefixing.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/renaming_overrides_prefixing.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/reserved.zig b/tests/expectations/reserved.zig new file mode 100644 index 000000000..a85f06f1e --- /dev/null +++ b/tests/expectations/reserved.zig @@ -0,0 +1,34 @@ +const std = @import("std"); + +pub const A = extern struct { + namespace_: i32, + float_: f32, +}; + +pub const B = extern struct { + namespace_: i32, + float_: f32, +}; + +pub const C_Tag = enum { + D, +}; + +pub const D_Body = extern struct { + namespace_: i32, + float_: f32, +}; + +pub const C = extern struct { + tag: C_Tag, +}; + +pub const E_Tag = enum { + Double, + Float, +}; + +pub const E = extern struct { + tag: E_Tag, + float_: f32, +}; \ No newline at end of file diff --git a/tests/expectations/sentinel.zig b/tests/expectations/sentinel.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/sentinel.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/simplify_option_ptr.zig b/tests/expectations/simplify_option_ptr.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/simplify_option_ptr.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/size_types.zig b/tests/expectations/size_types.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/size_types.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/static.zig b/tests/expectations/static.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/static.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/std_lib.zig b/tests/expectations/std_lib.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/std_lib.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/struct.zig b/tests/expectations/struct.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/struct.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/struct_literal.zig b/tests/expectations/struct_literal.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/struct_literal.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/style_crash.zig b/tests/expectations/style_crash.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/style_crash.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/swift_name.zig b/tests/expectations/swift_name.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/swift_name.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/transform_op.zig b/tests/expectations/transform_op.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/transform_op.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/transparent.zig b/tests/expectations/transparent.zig new file mode 100644 index 000000000..252ed751d --- /dev/null +++ b/tests/expectations/transparent.zig @@ -0,0 +1,25 @@ +const std = @import("std"); + +const DummyStruct = opaque {}; + +const EnumWithAssociatedConstantInImpl = opaque {}; + +pub const TransparentComplexWrappingStructTuple = DummyStruct; + +pub const TransparentPrimitiveWrappingStructTuple = u32; + +pub const TransparentComplexWrappingStructure = DummyStruct; + +pub const TransparentPrimitiveWrappingStructure = u32; + +pub const TransparentComplexWrapper_i32 = DummyStruct; + +pub const TransparentPrimitiveWrapper_i32 = u32; + +pub const TransparentPrimitiveWithAssociatedConstants = u32; +pub const TransparentPrimitiveWithAssociatedConstants_ZERO = 0; +pub const TransparentPrimitiveWithAssociatedConstants_ONE = 1; + +pub const EnumWithAssociatedConstantInImpl_TEN = 10; + +extern fn root(a: TransparentComplexWrappingStructTuple, b: TransparentPrimitiveWrappingStructTuple, c: TransparentComplexWrappingStructure, d: TransparentPrimitiveWrappingStructure, e: TransparentComplexWrapper_i32, f: TransparentPrimitiveWrapper_i32, g: TransparentPrimitiveWithAssociatedConstants, h: EnumWithAssociatedConstantInImpl) anyopaque; diff --git a/tests/expectations/typedef.zig b/tests/expectations/typedef.zig new file mode 100644 index 000000000..69ab58042 --- /dev/null +++ b/tests/expectations/typedef.zig @@ -0,0 +1,10 @@ +const std = @import("std"); + +pub const Foo_i32__i32 = extern struct { + x: i32, + y: i32, +}; + +pub const IntFoo_i32 = Foo_i32__i32; + +extern fn root(a: IntFoo_i32) anyopaque; diff --git a/tests/expectations/union.zig b/tests/expectations/union.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/union.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/va_list.zig b/tests/expectations/va_list.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/va_list.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/workspace.zig b/tests/expectations/workspace.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/workspace.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/zst.zig b/tests/expectations/zst.zig new file mode 100644 index 000000000..191e35d9c --- /dev/null +++ b/tests/expectations/zst.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const TraitObject = extern struct { + data: ?*anyopaque, + vtable: ?*anyopaque, +}; + +extern fn root(ptr: ?*const anyopaque, t: TraitObject) ?*anyopaque; diff --git a/tests/tests.rs b/tests/tests.rs index 3b44eac3c..f79bc55f6 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -36,6 +36,9 @@ fn run_cbindgen( Language::Cython => { command.arg("--lang").arg("cython"); } + Language::Zig => { + command.arg("--lang").arg("zig"); + } } if let Some(style) = style { @@ -72,6 +75,7 @@ fn compile( Language::Cxx => env::var("CXX").unwrap_or_else(|_| "g++".to_owned()), Language::C => env::var("CC").unwrap_or_else(|_| "gcc".to_owned()), Language::Cython => env::var("CYTHON").unwrap_or_else(|_| "cython".to_owned()), + Language::Zig => env::var("ZIG").unwrap_or_else(|_| "zig".to_owned()), }; let file_name = cbindgen_output @@ -129,6 +133,13 @@ fn compile( command.arg("-o").arg(&object); command.arg(cbindgen_output); } + Language::Zig => { + command.arg("build-obj"); + command.arg("-O").arg("ReleaseSafe"); + command.arg("-fsingle-threaded"); + command.arg("-name").arg(&object); + command.arg("-femit-bin").arg(cbindgen_output); + } } println!("Running: {:?}", command); @@ -173,6 +184,7 @@ fn run_compile_test( // is extension-sensitive and won't work on them, so we use implementation files (`.pyx`) // in the test suite. Language::Cython => ".pyx", + Language::Zig => ".zig", }; let skip_warning_as_error = name.rfind(SKIP_WARNING_AS_ERROR_SUFFIX).is_some();