Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cargo/config-windows.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build]
target = "x86_64-pc-windows-msvc"
rustflags = ["-C", "target-feature=+crt-static"]
8 changes: 0 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ jobs:
if: ${{ runner.os == 'Windows' }}
shell: pwsh
run: Copy-Item -Path .cargo/config-windows.toml -Destination .cargo/config.toml
- name: Copy Linux config
if: ${{ runner.os == 'Linux' }}
shell: pwsh
run: Copy-Item -Path .cargo/config-linux.toml -Destination .cargo/config.toml
- name: Caching
uses: Swatinem/rust-cache@v1
- name: Download Cargo.lock
Expand Down Expand Up @@ -140,10 +136,6 @@ jobs:
if: ${{ runner.os == 'Windows' }}
shell: pwsh
run: Copy-Item -Path .cargo/config-windows.toml -Destination .cargo/config.toml
- name: Copy Linux config
if: ${{ runner.os == 'Linux' }}
shell: pwsh
run: Copy-Item -Path .cargo/config-linux.toml -Destination .cargo/config.toml
- name: Caching
uses: Swatinem/rust-cache@v1
- name: Download Cargo.lock
Expand Down
2 changes: 1 addition & 1 deletion generators/java-oo-bindgen/src/java/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ fn generate_destructor(
f.newline()?;

f.writeln(&format!(
"{}.{}(this);",
"{}.Wrapped.{}(this);",
NATIVE_FUNCTIONS_CLASSNAME, destructor.function.name
))
})?;
Expand Down
2 changes: 1 addition & 1 deletion generators/java-oo-bindgen/src/java/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ pub(crate) fn call_native_function(
}

f.write(&format!(
"{}.{}({});",
"{}.Wrapped.{}({});",
NATIVE_FUNCTIONS_CLASSNAME, method.name, params
))?;

Expand Down
73 changes: 71 additions & 2 deletions generators/java-oo-bindgen/src/java/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::JavaBindgenConfig;

use self::conversion::*;
use self::formatting::*;
use crate::java::nullable::{IsStruct, Nullable};

mod class;
mod constant;
Expand All @@ -16,6 +17,7 @@ mod enumeration;
mod exception;
mod formatting;
mod interface;
mod nullable;
mod structure;

const NATIVE_FUNCTIONS_CLASSNAME: &str = "NativeFunctions";
Expand Down Expand Up @@ -215,6 +217,23 @@ fn generate_pom(lib: &Library, config: &JavaBindgenConfig) -> FormattingResult<(
f.writeln("</project>")
}

fn write_null_checks(
f: &mut dyn Printer,
args: &[Arg<FunctionArgument, Validated>],
) -> FormattingResult<()> {
for arg in args.iter().filter(|a| a.arg_type.is_nullable()) {
let arg_name = arg.name.mixed_case();
f.writeln(&format!(
"java.util.Objects.requireNonNull({}, \"{} cannot be null\");",
arg_name, arg_name
))?;
if arg.arg_type.is_struct() {
f.writeln(&format!("{}._assertFieldsNotNull();", arg_name))?;
}
}
Ok(())
}

fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> FormattingResult<()> {
let mut f = create_file(NATIVE_FUNCTIONS_CLASSNAME, config, lib)?;

Expand Down Expand Up @@ -322,15 +341,21 @@ fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> Form

for handle in lib.functions().filter(|func| !skip(func.category)) {
f.writeln(&format!(
"static native {} {}(",
"private static native {} {}(",
handle.return_type.as_java_primitive(),
handle.name
))?;

let args = handle
.arguments
.iter()
.map(|param| format!("{} {}", param.arg_type.as_java_primitive(), param.name))
.map(|param| {
format!(
"{} {}",
param.arg_type.as_java_primitive(),
param.name.mixed_case()
)
})
.collect::<Vec<String>>()
.join(", ");

Expand All @@ -339,6 +364,50 @@ fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> Form
f.newline()?;
}

f.writeln("// wrappers around the native functions that do null checking")?;
f.writeln("static class Wrapped")?;
blocked(f, |f| {
for handle in lib.functions().filter(|func| !skip(func.category)) {
f.writeln(&format!(
"static {} {}(",
handle.return_type.as_java_primitive(),
handle.name
))?;

let args = handle
.arguments
.iter()
.map(|param| {
format!(
"{} {}",
param.arg_type.as_java_primitive(),
param.name.mixed_case()
)
})
.collect::<Vec<String>>()
.join(", ");

f.write(&args)?;
f.write(")")?;
blocked(f, |f| {
write_null_checks(f, &handle.arguments)?;
let arg_names = handle
.arguments
.iter()
.map(|x| x.name.mixed_case())
.collect::<Vec<String>>()
.join(", ");
let invocation = format!("NativeFunctions.{}({});", handle.name, arg_names);
if handle.return_type.is_some() {
f.writeln(&format!("return {}", invocation))
} else {
f.writeln(&invocation)
}
})?;
}
Ok(())
})?;

Ok(())
})
}
Expand Down
151 changes: 151 additions & 0 deletions generators/java-oo-bindgen/src/java/nullable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use oo_bindgen::model::{
BasicType, CallbackArgStructField, FunctionArgStructField, FunctionArgument,
FunctionReturnStructField, Primitive, UniversalStructField,
};

pub(crate) trait Nullable {
fn is_nullable(&self) -> bool;
}

pub(crate) trait IsStruct {
fn is_struct(&self) -> bool;
}

impl Nullable for Primitive {
// the unsigned types are wrapper objects
fn is_nullable(&self) -> bool {
match self {
Primitive::Bool => false,
Primitive::U8 => true,
Primitive::S8 => false,
Primitive::U16 => true,
Primitive::S16 => false,
Primitive::U32 => true,
Primitive::S32 => false,
Primitive::U64 => true,
Primitive::S64 => false,
Primitive::Float => false,
Primitive::Double => false,
}
}
}

impl Nullable for BasicType {
fn is_nullable(&self) -> bool {
match self {
BasicType::Primitive(x) => x.is_nullable(),
BasicType::Duration(_) => true,
BasicType::Enum(_) => true,
}
}
}

impl Nullable for FunctionArgument {
fn is_nullable(&self) -> bool {
match self {
Self::Basic(x) => x.is_nullable(),
Self::String(_) => true,
Self::Collection(_) => true,
Self::Struct(_) => true,
Self::StructRef(_) => true,
Self::ClassRef(_) => true,
Self::Interface(_) => true,
}
}
}

impl Nullable for FunctionArgStructField {
fn is_nullable(&self) -> bool {
match self {
FunctionArgStructField::Basic(x) => x.is_nullable(),
FunctionArgStructField::String(_) => true,
FunctionArgStructField::Interface(_) => true,
FunctionArgStructField::Struct(_) => true,
}
}
}

impl Nullable for FunctionReturnStructField {
fn is_nullable(&self) -> bool {
match self {
FunctionReturnStructField::Basic(x) => x.is_nullable(),
FunctionReturnStructField::ClassRef(_) => true,
FunctionReturnStructField::Iterator(_) => true,
FunctionReturnStructField::Struct(_) => true,
}
}
}

impl Nullable for CallbackArgStructField {
fn is_nullable(&self) -> bool {
match self {
CallbackArgStructField::Basic(x) => x.is_nullable(),
CallbackArgStructField::Iterator(_) => true,
CallbackArgStructField::Struct(_) => true,
}
}
}

impl Nullable for UniversalStructField {
fn is_nullable(&self) -> bool {
match self {
UniversalStructField::Basic(x) => x.is_nullable(),
UniversalStructField::Struct(_) => true,
}
}
}

impl IsStruct for FunctionArgStructField {
fn is_struct(&self) -> bool {
match self {
FunctionArgStructField::Basic(_) => false,
FunctionArgStructField::String(_) => false,
FunctionArgStructField::Interface(_) => false,
FunctionArgStructField::Struct(_) => true,
}
}
}

impl IsStruct for FunctionReturnStructField {
fn is_struct(&self) -> bool {
match self {
FunctionReturnStructField::Basic(_) => false,
FunctionReturnStructField::ClassRef(_) => false,
FunctionReturnStructField::Iterator(_) => false,
FunctionReturnStructField::Struct(_) => true,
}
}
}

impl IsStruct for CallbackArgStructField {
fn is_struct(&self) -> bool {
match self {
CallbackArgStructField::Basic(_) => false,
CallbackArgStructField::Iterator(_) => false,
CallbackArgStructField::Struct(_) => true,
}
}
}

impl IsStruct for UniversalStructField {
fn is_struct(&self) -> bool {
match self {
UniversalStructField::Basic(_) => false,
UniversalStructField::Struct(_) => true,
}
}
}

impl IsStruct for FunctionArgument {
fn is_struct(&self) -> bool {
match self {
FunctionArgument::Basic(_) => false,
FunctionArgument::String(_) => false,
FunctionArgument::Collection(_) => false,
FunctionArgument::Struct(_) => true,
FunctionArgument::StructRef(_) => true,
FunctionArgument::ClassRef(_) => false,
FunctionArgument::Interface(_) => false,
}
}
}
28 changes: 26 additions & 2 deletions generators/java-oo-bindgen/src/java/structure.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::doc::*;
use super::*;
use crate::java::nullable::IsStruct;

fn constructor_visibility(struct_type: Visibility) -> &'static str {
match struct_type {
Expand Down Expand Up @@ -181,9 +182,31 @@ where
Ok(())
}

fn write_null_checker<T>(f: &mut dyn Printer, handle: &Struct<T, Validated>) -> FormattingResult<()>
where
T: StructFieldType + Nullable + IsStruct,
{
f.writeln("void _assertFieldsNotNull()")?;
blocked(f, |f| {
for field in handle.fields.iter() {
if field.field_type.is_nullable() {
let field_name = field.name.mixed_case();
f.writeln(&format!(
"java.util.Objects.requireNonNull({}, \"{} cannot be null\");",
field_name, field_name
))?;
if field.field_type.is_struct() {
f.writeln(&format!("{}._assertFieldsNotNull();", field_name))?;
}
}
}
Ok(())
})
}

pub(crate) fn generate<T>(f: &mut dyn Printer, st: &Struct<T, Validated>) -> FormattingResult<()>
where
T: StructFieldType + JavaType,
T: StructFieldType + JavaType + Nullable + IsStruct,
{
let struct_name = st.name().camel_case();

Expand Down Expand Up @@ -238,6 +261,7 @@ where
write_constructor(f, Visibility::Private, st, &constructor)?;
}

Ok(())
f.newline()?;
write_null_checker(f, st)
})
}
Loading