Skip to content

Commit

Permalink
Add custom destructor name.
Browse files Browse the repository at this point in the history
  • Loading branch information
emgre committed Apr 26, 2021
1 parent d87ce22 commit 7196755
Show file tree
Hide file tree
Showing 21 changed files with 150 additions and 74 deletions.
2 changes: 1 addition & 1 deletion ci-script/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "ci-script"
version = "0.1.0"
authors = ["Émile Grégoire <emile@automatak.com>"]
authors = ["Émile Grégoire <emile@stepfunc.io>"]
edition = "2018"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion generators/c-oo-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "c-oo-bindgen"
version = "0.1.0"
authors = ["Émile Grégoire <emile@automatak.com>"]
authors = ["Émile Grégoire <emile@stepfunc.io>"]
edition = "2018"

[dependencies]
Expand Down
10 changes: 9 additions & 1 deletion generators/c-oo-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,15 @@ pub fn generate_doxygen(lib: &Library, config: &CBindgenConfig) -> FormattingRes
stdin.write_all(b"HTML_OUTPUT = doc\n").unwrap();
stdin.write_all(b"GENERATE_LATEX = NO\n").unwrap();
stdin.write_all(b"EXTRACT_STATIC = YES\n").unwrap();
stdin.write_all(b"INPUT = include\n").unwrap();
stdin
.write_all(
&format!(
"INPUT = {}/include\n",
config.platforms.iter().next().unwrap().platform.to_string()
)
.into_bytes(),
)
.unwrap();
}

command.wait()?;
Expand Down
2 changes: 1 addition & 1 deletion generators/dotnet-oo-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "dotnet-oo-bindgen"
version = "0.1.0"
authors = ["Émile Grégoire <emile@automatak.com>"]
authors = ["Émile Grégoire <emile@stepfunc.io>"]
edition = "2018"

[dependencies]
Expand Down
22 changes: 11 additions & 11 deletions generators/dotnet-oo-bindgen/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub(crate) fn generate(
})?;

f.writeln(&format!("public sealed class {}", classname))?;
if class.is_manual_destruction() {
if matches!(class.destruction_mode, DestructionMode::Dispose) {
f.write(": IDisposable")?;
}

Expand Down Expand Up @@ -55,13 +55,7 @@ pub(crate) fn generate(
}

if let Some(destructor) = &class.destructor {
generate_destructor(
f,
&classname,
destructor,
class.is_manual_destruction(),
lib,
)?;
generate_destructor(f, &classname, destructor, &class.destruction_mode, lib)?;
f.newline()?;
}

Expand Down Expand Up @@ -177,14 +171,20 @@ fn generate_destructor(
f: &mut dyn Printer,
classname: &str,
destructor: &NativeFunctionHandle,
is_manual_destruction: bool,
destruction_mode: &DestructionMode,
lib: &Library,
) -> FormattingResult<()> {
if is_manual_destruction {
if destruction_mode.is_manual_destruction() {
// Public Dispose method
documentation(f, |f| xmldoc_print(f, &destructor.doc, lib))?;

f.writeln("public void Dispose()")?;
let method_name = if let DestructionMode::Custom(name) = destruction_mode {
name.to_camel_case()
} else {
"Dispose".to_string()
};

f.writeln(&format!("public void {}()", method_name))?;
blocked(f, |f| {
f.writeln("Dispose(true);")?;
f.writeln("GC.SuppressFinalize(this);")
Expand Down
14 changes: 12 additions & 2 deletions generators/dotnet-oo-bindgen/src/doc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::conversion::*;
use heck::{CamelCase, MixedCase};
use oo_bindgen::class::DestructionMode;
use oo_bindgen::doc::*;
use oo_bindgen::formatting::*;
use oo_bindgen::Library;
Expand Down Expand Up @@ -86,9 +87,18 @@ fn reference_print(
))?;
}
DocReference::ClassDestructor(class_name) => {
let class = lib.find_class(class_name).unwrap();

let method_name = if let DestructionMode::Custom(name) = &class.destruction_mode {
name.to_camel_case()
} else {
"Dispose".to_string()
};

f.write(&format!(
"<see cref=\"{}.Dispose()\" />",
class_name.to_camel_case()
"<see cref=\"{}.{}()\" />",
class_name.to_camel_case(),
method_name,
))?;
}
DocReference::Struct(struct_name) => {
Expand Down
2 changes: 1 addition & 1 deletion generators/java-oo-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "java-oo-bindgen"
version = "0.1.0"
authors = ["Émile Grégoire <emile@automatak.com>"]
authors = ["Émile Grégoire <emile@stepfunc.io>"]
edition = "2018"

[dependencies]
Expand Down
36 changes: 24 additions & 12 deletions generators/java-oo-bindgen/src/java/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) fn generate(

// Class definition
f.writeln(&format!("public final class {}", classname))?;
if class.is_manual_destruction() {
if matches!(class.destruction_mode, DestructionMode::Dispose) {
f.write(" implements AutoCloseable")?;
}

Expand All @@ -39,7 +39,7 @@ pub(crate) fn generate(
}

if let Some(destructor) = &class.destructor {
generate_destructor(f, destructor, class.is_manual_destruction(), lib)?;
generate_destructor(f, destructor, &class.destruction_mode, lib)?;
f.newline()?;
}

Expand Down Expand Up @@ -145,10 +145,10 @@ fn generate_constructor(
fn generate_destructor(
f: &mut dyn Printer,
destructor: &NativeFunctionHandle,
is_manual_destruction: bool,
destruction_mode: &DestructionMode,
lib: &Library,
) -> FormattingResult<()> {
if is_manual_destruction {
if destruction_mode.is_manual_destruction() {
documentation(f, |f| {
// Print top-level documentation
javadoc_print(f, &destructor.doc, lib)?;
Expand All @@ -164,12 +164,18 @@ fn generate_destructor(
})?;
}

if is_manual_destruction {
// AutoCloseable implementation
f.writeln("@Override")?;
f.writeln("public void close()")?;
} else {
f.writeln("private void close()")?;
match destruction_mode {
DestructionMode::Automatic => {
f.writeln("private void close()")?;
}
DestructionMode::Custom(name) => {
f.writeln(&format!("public void {}()", name.to_mixed_case()))?;
}
DestructionMode::Dispose => {
// AutoCloseable implementation
f.writeln("@Override")?;
f.writeln("public void close()")?;
}
}

blocked(f, |f| {
Expand All @@ -186,10 +192,16 @@ fn generate_destructor(

f.newline()?;

// Dispose method
// Finalizer method
f.writeln("@Override")?;
f.writeln("public void finalize()")?;
blocked(f, |f| f.writeln("this.close();"))
blocked(f, |f| {
if let DestructionMode::Custom(name) = destruction_mode {
f.writeln(&format!("this.{}();", name.to_mixed_case()))
} else {
f.writeln("this.close();")
}
})
}

fn generate_method(f: &mut dyn Printer, method: &Method, lib: &Library) -> FormattingResult<()> {
Expand Down
15 changes: 14 additions & 1 deletion generators/java-oo-bindgen/src/java/doc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::conversion::*;
use heck::{CamelCase, MixedCase, ShoutySnakeCase};
use oo_bindgen::class::DestructionMode;
use oo_bindgen::doc::*;
use oo_bindgen::formatting::*;
use oo_bindgen::Library;
Expand Down Expand Up @@ -83,7 +84,19 @@ fn reference_print(
))?;
}
DocReference::ClassDestructor(class_name) => {
f.write(&format!("{{@link {}#close}}", class_name.to_camel_case()))?;
let class = lib.find_class(class_name).unwrap();

let method_name = if let DestructionMode::Custom(name) = &class.destruction_mode {
name.to_mixed_case()
} else {
"close".to_string()
};

f.write(&format!(
"{{@link {}#{}}}",
class_name.to_camel_case(),
method_name
))?;
}
DocReference::Struct(struct_name) => {
f.write(&format!("{{@link {}}}", struct_name.to_camel_case()))?;
Expand Down
2 changes: 1 addition & 1 deletion generators/rust-oo-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "rust-oo-bindgen"
version = "0.1.0"
authors = ["Émile Grégoire <emile@automatak.com>"]
authors = ["Émile Grégoire <emile@stepfunc.io>"]
edition = "2018"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion oo-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "oo-bindgen"
version = "0.1.0"
authors = ["Émile Grégoire <emile@automatak.com>"]
authors = ["Émile Grégoire <emile@stepfunc.io>"]
edition = "2018"

[dependencies]
Expand Down
45 changes: 37 additions & 8 deletions oo-bindgen/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,32 @@ pub struct AsyncMethod {
pub callback_param_name: String,
}

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum DestructionMode {
/// Object is automatically deleted by the GC
Automatic,
/// Object is disposed of manually by calling a custom method
///
/// For safety, if the user never calls the destruction method, the object
/// will still be deleted by the GC at some point. However, it is
/// strongly advised to take care of the destruction manually.
Custom(String),
/// Object is disposed of manually by calling a dispose()/close() method
///
/// For safety, if the user never calls the destruction method, the object
/// will still be deleted by the GC at some point. However, it is
/// strongly advised to take care of the destruction manually.
Manual,
Dispose,
}

impl DestructionMode {
pub fn is_manual_destruction(&self) -> bool {
match self {
Self::Automatic => false,
Self::Custom(_) => true,
Self::Dispose => true,
}
}
}

/// Object-oriented class definition
Expand All @@ -67,10 +83,6 @@ impl Class {
self.declaration.clone()
}

pub fn is_manual_destruction(&self) -> bool {
self.destruction_mode == DestructionMode::Manual && self.destructor.is_some()
}

pub fn find_method<T: AsRef<str>>(&self, method_name: T) -> Option<&NativeFunctionHandle> {
for method in &self.methods {
if method.name == method_name.as_ref() {
Expand Down Expand Up @@ -291,8 +303,25 @@ impl<'a> ClassBuilder<'a> {
Ok(self)
}

pub fn manual_destroy(mut self) -> Result<Self> {
self.destruction_mode = DestructionMode::Manual;
pub fn custom_destroy<T: Into<String>>(mut self, name: T) -> Result<Self> {
if self.destructor.is_none() {
return Err(BindingError::NoDestructorForManualDestruction {
handle: self.declaration,
});
}

self.destruction_mode = DestructionMode::Custom(name.into());
Ok(self)
}

pub fn disposable_destroy(mut self) -> Result<Self> {
if self.destructor.is_none() {
return Err(BindingError::NoDestructorForManualDestruction {
handle: self.declaration,
});
}

self.destruction_mode = DestructionMode::Dispose;
Ok(self)
}

Expand Down
2 changes: 2 additions & 0 deletions oo-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ pub enum BindingError {
},
#[error("Destructor for class '{}' cannot fail", handle.name)]
DestructorCannotFail { handle: ClassDeclarationHandle },
#[error("No destructor defined for class '{}', but asking for manual/disposable destruction", handle.name)]
NoDestructorForManualDestruction { handle: ClassDeclarationHandle },

// Async errors
#[error("Native function '{}' cannot be used as an async method because it doesn't have a interface parameter", handle.name)]
Expand Down
30 changes: 15 additions & 15 deletions tests/bindings/dotnet/foo.Tests/ClassTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,29 @@ public void ConstructionDestructionTest()
{
Assert.Equal(0u, TestClass.ConstructionCounter());

using(var testclass = new TestClass(41))
{
Assert.Equal(1u, TestClass.ConstructionCounter());
Assert.Equal(41u, testclass.GetValue());
var testclass = new TestClass(41);
Assert.Equal(1u, TestClass.ConstructionCounter());
Assert.Equal(41u, testclass.GetValue());

testclass.IncrementValue();
Assert.Equal(42u, testclass.GetValue());
}
testclass.IncrementValue();
Assert.Equal(42u, testclass.GetValue());

testclass.Delete();

Assert.Equal(0u, TestClass.ConstructionCounter());
}

[Fact]
public async void AsyncMethodTest()
{
using (var testclass = new TestClass(41))
{
Assert.Equal(1u, TestClass.ConstructionCounter());
Assert.Equal(41u, await testclass.GetValueAsync());

testclass.IncrementValue();
Assert.Equal(42u, await testclass.GetValueAsync());
}
var testclass = new TestClass(41);
Assert.Equal(1u, TestClass.ConstructionCounter());
Assert.Equal(41u, await testclass.GetValueAsync());

testclass.IncrementValue();
Assert.Equal(42u, await testclass.GetValueAsync());

testclass.Delete();
}
}
}
Loading

0 comments on commit 7196755

Please sign in to comment.