Skip to content

Commit 28ca1ae

Browse files
authored
Add error handling (#49)
1 parent b2fa032 commit 28ca1ae

File tree

42 files changed

+2134
-764
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2134
-764
lines changed

.github/workflows/ci.yml

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,78 +16,119 @@ jobs:
1616
- stable
1717
- beta
1818
- nightly
19-
toolchain:
20-
- default
21-
- musl
22-
exclude:
23-
- os: windows-latest
24-
toolchain: musl
2519
runs-on: ${{ matrix.os }}
2620
steps:
2721
- name: Checkout
2822
uses: actions/checkout@v1
2923
- name: Install Rust ${{ matrix.rust }}
30-
if: ${{ matrix.toolchain != 'musl' }}
3124
uses: actions-rs/toolchain@v1
3225
with:
3326
profile: minimal
3427
toolchain: ${{ matrix.rust }}
3528
override: true
36-
- name: Install Rust ${{ matrix.rust }} (musl)
37-
if: ${{ matrix.toolchain == 'musl' }}
29+
- name: Copy Windows config
30+
if: ${{ runner.os == 'Windows' }}
31+
shell: pwsh
32+
run: Copy-Item -Path .cargo/config-windows.toml -Destination .cargo/config.toml
33+
- name: Copy Linux config
34+
if: ${{ runner.os == 'Linux' }}
35+
shell: pwsh
36+
run: Copy-Item -Path .cargo/config-linux.toml -Destination .cargo/config.toml
37+
- name: Caching
38+
uses: Swatinem/rust-cache@v1
39+
- name: Run Rust unit tests
40+
uses: actions-rs/cargo@v1
41+
with:
42+
command: test
43+
linting:
44+
strategy:
45+
fail-fast: false
46+
matrix:
47+
rust:
48+
- stable
49+
- beta
50+
runs-on: ubuntu-latest
51+
steps:
52+
- name: Checkout
53+
uses: actions/checkout@v1
54+
- name: Install Rust ${{ matrix.rust }}
3855
uses: actions-rs/toolchain@v1
3956
with:
4057
profile: minimal
4158
toolchain: ${{ matrix.rust }}
42-
target: x86_64-unknown-linux-musl
59+
override: true
60+
components: rustfmt, clippy
61+
- name: Caching
62+
uses: Swatinem/rust-cache@v1
63+
- name: Format
64+
uses: actions-rs/cargo@v1
65+
with:
66+
command: fmt
67+
args: --all -- --check
68+
- name: Clippy
69+
uses: actions-rs/cargo@v1
70+
with:
71+
command: clippy
72+
args: -- -D warnings
73+
bindings:
74+
strategy:
75+
fail-fast: false
76+
matrix:
77+
os:
78+
- ubuntu-latest
79+
- windows-latest
80+
runs-on: ${{ matrix.os }}
81+
steps:
82+
- name: Checkout
83+
uses: actions/checkout@v1
84+
- name: Install Rust
85+
uses: actions-rs/toolchain@v1
86+
with:
87+
profile: minimal
88+
toolchain: stable
4389
override: true
4490
- name: Copy Windows config
4591
if: ${{ runner.os == 'Windows' }}
4692
shell: pwsh
4793
run: Copy-Item -Path .cargo/config-windows.toml -Destination .cargo/config.toml
4894
- name: Copy Linux config
49-
if: ${{ runner.os == 'Linux' && matrix.toolchain == 'default' }}
95+
if: ${{ runner.os == 'Linux' }}
5096
shell: pwsh
5197
run: Copy-Item -Path .cargo/config-linux.toml -Destination .cargo/config.toml
52-
- name: Copy Linux musl config
53-
if: ${{ runner.os == 'Linux' && matrix.toolchain == 'musl' }}
54-
shell: pwsh
55-
run: Copy-Item -Path .cargo/config-linux-musl.toml -Destination .cargo/config.toml
56-
- name: Run Rust unit tests
98+
- name: Caching
99+
uses: Swatinem/rust-cache@v1
100+
- name: Build
57101
uses: actions-rs/cargo@v1
58102
with:
59103
command: test
104+
args: --release
60105
- name: C bindings
61106
uses: actions-rs/cargo@v1
62107
with:
63108
command: run
64109
args: --release --bin foo-bindings -- --c
65110
- name: .NET bindings
66-
if: ${{ matrix.toolchain != 'musl' }}
67111
uses: actions-rs/cargo@v1
68112
with:
69113
command: run
70114
args: --release --bin foo-bindings -- --dotnet
71115
- name: Java bindings
72-
if: ${{ matrix.toolchain != 'musl' }}
73116
uses: actions-rs/cargo@v1
74117
with:
75118
command: run
76119
args: --release --bin foo-bindings -- --java
77-
- name: Upload compiled bindings
78-
if: ${{ matrix.rust == 'stable' }}
120+
- name: Upload compiled C bindings
79121
uses: actions/upload-artifact@v2
80122
with:
81123
name: ffi-modules
82124
path: tests/bindings/c/generated/lib
83125
- name: Upload compiled Java bindings
84-
if: ${{ matrix.rust == 'stable' && matrix.toolchain != 'musl' }}
85126
uses: actions/upload-artifact@v2
86127
with:
87128
name: ffi-modules
88129
path: tests/bindings/java/foo/src/main/resources
89130
packaging:
90-
needs: test
131+
needs: bindings
91132
runs-on: ubuntu-latest
92133
steps:
93134
- name: Checkout
@@ -98,6 +139,8 @@ jobs:
98139
profile: minimal
99140
toolchain: stable
100141
override: true
142+
- name: Caching
143+
uses: Swatinem/rust-cache@v1
101144
- name: Download compiled FFI
102145
uses: actions/download-artifact@v2
103146
with:
@@ -107,7 +150,7 @@ jobs:
107150
uses: actions-rs/cargo@v1
108151
with:
109152
command: run
110-
args: --release --bin foo-bindings -- --package ./ffi-modules
153+
args: --bin foo-bindings -- --package ./ffi-modules
111154
- name: Upload C bindings
112155
uses: actions/upload-artifact@v2
113156
with:
@@ -123,32 +166,3 @@ jobs:
123166
with:
124167
name: java-bindings
125168
path: tests/bindings/java/foo/target/*.jar
126-
linting:
127-
strategy:
128-
fail-fast: false
129-
matrix:
130-
rust:
131-
- stable
132-
- beta
133-
- nightly
134-
runs-on: ubuntu-latest
135-
steps:
136-
- name: Checkout
137-
uses: actions/checkout@v1
138-
- name: Install Rust ${{ matrix.rust }}
139-
uses: actions-rs/toolchain@v1
140-
with:
141-
profile: minimal
142-
toolchain: ${{ matrix.rust }}
143-
override: true
144-
components: rustfmt, clippy
145-
- name: Format
146-
uses: actions-rs/cargo@v1
147-
with:
148-
command: fmt
149-
args: --all -- --check
150-
- name: Clippy
151-
uses: actions-rs/cargo@v1
152-
with:
153-
command: clippy
154-
args: -- -D warnings

ci-script/src/lib.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,21 @@ pub fn run(settings: BindingBuilderSettings) {
5252
let run_java = matches.is_present("java");
5353
let run_all = !run_c && !run_dotnet && !run_java;
5454

55+
let package = matches.is_present("package");
5556
let package_src = matches.value_of("package");
5657

5758
if run_c || run_all {
58-
let builder = run_builder::<CBindingBuilder>(&settings, run_tests, package_src);
59+
let builder = run_builder::<CBindingBuilder>(&settings, run_tests, package, package_src);
5960

6061
if matches.is_present("doxygen") {
6162
builder.build_doxygen();
6263
}
6364
}
6465
if run_dotnet || run_all {
65-
run_builder::<DotnetBindingBuilder>(&settings, run_tests, package_src);
66+
run_builder::<DotnetBindingBuilder>(&settings, run_tests, package, package_src);
6667
}
6768
if run_java || run_all {
68-
run_builder::<JavaBindingBuilder>(&settings, run_tests, package_src);
69+
run_builder::<JavaBindingBuilder>(&settings, run_tests, package, package_src);
6970
}
7071
}
7172

@@ -76,6 +77,7 @@ fn ffi_path() -> PathBuf {
7677
fn run_builder<'a, B: BindingBuilder<'a>>(
7778
settings: &'a BindingBuilderSettings,
7879
run_tests: bool,
80+
package: bool,
7981
package_src: Option<&str>,
8082
) -> B {
8183
let mut platforms = PlatformLocations::new();
@@ -120,9 +122,9 @@ fn run_builder<'a, B: BindingBuilder<'a>>(
120122
return builder;
121123
}
122124

123-
builder.generate(package_src.is_some());
125+
builder.generate(package);
124126

125-
if package_src.is_none() {
127+
if !package {
126128
builder.build();
127129
if run_tests {
128130
builder.test();
@@ -333,12 +335,13 @@ impl<'a> BindingBuilder<'a> for DotnetBindingBuilder<'a> {
333335
}
334336

335337
fn package(&mut self) {
336-
// Run unit tests
338+
// Produce a nupkg
337339
let result = Command::new("dotnet")
338340
.current_dir(&self.output_dir())
339341
.arg("pack")
340342
.arg("--configuration")
341343
.arg("Release")
344+
.arg("--include-symbols")
342345
.arg("--output")
343346
.arg("nupkg")
344347
.status()

generators/c-oo-bindgen/src/lib.rs

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ impl CFormatting for Symbol {
113113
Symbol::Struct(handle) => handle.declaration().to_c_type(),
114114
Symbol::Enum(handle) => handle.to_c_type(),
115115
Symbol::Class(handle) => handle.declaration().to_c_type(),
116+
Symbol::StaticClass(_) => panic!("static classes cannot be referenced in C"),
116117
Symbol::Interface(handle) => handle.to_c_type(),
117118
Symbol::OneTimeCallback(handle) => handle.to_c_type(),
118119
Symbol::Iterator(handle) => handle.iter_type.to_c_type(),
@@ -577,7 +578,7 @@ fn write_class_declaration(
577578
))
578579
}
579580

580-
fn write_function(
581+
fn write_function_docs(
581582
f: &mut dyn Printer,
582583
handle: &NativeFunctionHandle,
583584
lib: &Library,
@@ -592,22 +593,50 @@ fn write_function(
592593
docstring_print(f, &param.doc, lib)?;
593594
}
594595

595-
// Print return documentation
596-
if let ReturnType::Type(_, doc) = &handle.return_type {
597-
f.writeln("@return ")?;
598-
docstring_print(f, doc, lib)?;
596+
fn write_error_return_doc(f: &mut dyn Printer) -> FormattingResult<()> {
597+
f.writeln("@return Error code")
598+
}
599+
600+
match handle.get_type() {
601+
NativeFunctionType::NoErrorNoReturn => {}
602+
NativeFunctionType::NoErrorWithReturn(_, doc) => {
603+
f.writeln("@return ")?;
604+
docstring_print(f, &doc, lib)?;
605+
}
606+
NativeFunctionType::ErrorNoReturn(_) => {
607+
write_error_return_doc(f)?;
608+
}
609+
NativeFunctionType::ErrorWithReturn(_, _, doc) => {
610+
f.writeln("@param out ")?;
611+
docstring_print(f, &doc, lib)?;
612+
write_error_return_doc(f)?;
613+
}
599614
}
600615

601616
Ok(())
602-
})?;
617+
})
618+
}
603619

604-
f.newline()?;
620+
fn write_function(
621+
f: &mut dyn Printer,
622+
handle: &NativeFunctionHandle,
623+
lib: &Library,
624+
) -> FormattingResult<()> {
625+
write_function_docs(f, handle, lib)?;
605626

606-
f.write(&format!(
607-
"{} {}(",
608-
CReturnType(&handle.return_type),
609-
handle.name
610-
))?;
627+
if let Some(error_type) = &handle.error_type {
628+
f.writeln(&format!(
629+
"{} {}(",
630+
CType(&Type::Enum(error_type.inner.clone())),
631+
handle.name
632+
))?;
633+
} else {
634+
f.writeln(&format!(
635+
"{} {}(",
636+
CReturnType(&handle.return_type),
637+
handle.name
638+
))?;
639+
}
611640

612641
f.write(
613642
&handle
@@ -624,6 +653,15 @@ fn write_function(
624653
.join(", "),
625654
)?;
626655

656+
if handle.error_type.is_some() {
657+
if let ReturnType::Type(x, _) = &handle.return_type {
658+
if !handle.parameters.is_empty() {
659+
f.write(", ")?;
660+
f.write(&format!("{}* out", CType(x)))?;
661+
}
662+
}
663+
}
664+
627665
f.write(");")
628666
}
629667

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Helpers
5+
{
6+
internal static class RustString
7+
{
8+
internal static IntPtr ToNative(string value)
9+
{
10+
var bytes = System.Text.Encoding.UTF8.GetBytes(value);
11+
var handle = Marshal.AllocHGlobal(bytes.Length + 1);
12+
// copy the bytes of the string
13+
Marshal.Copy(bytes, 0, handle, bytes.Length);
14+
// null terminator
15+
Marshal.WriteByte(handle, bytes.Length, 0);
16+
return handle;
17+
}
18+
19+
internal static void Destroy(IntPtr value)
20+
{
21+
Marshal.FreeHGlobal(value);
22+
}
23+
24+
internal static string FromNative(IntPtr value)
25+
{
26+
// figure out the length of the string by looking for the NULL terminator
27+
int length = 0;
28+
while (Marshal.ReadByte(value, length) != 0) ++length;
29+
byte[] buffer = new byte[length];
30+
// copy from the native type into the byte buffer
31+
Marshal.Copy(value, buffer, 0, length);
32+
return System.Text.Encoding.UTF8.GetString(buffer);
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)