Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Java bindings #705

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c1bb7a9
wip: java bindings
adjabaev Aug 19, 2024
21ec83d
Pretty much usable (there are missing functions such as remove and so…
adjabaev Aug 20, 2024
65db9eb
rust fmt formatting (did i figure it out?)
adjabaev Aug 20, 2024
4fe722b
Fix Clippy issues
adjabaev Aug 20, 2024
9891bbb
java: turn into a maven project
adjabaev Aug 20, 2024
47bea2e
java: implement a few tests to ensure everything is working as intended
adjabaev Aug 21, 2024
3eabd6c
rust-java: Add most of methods in TaffyTree
adjabaev Aug 21, 2024
587c810
rust: rustfmt
adjabaev Aug 21, 2024
81dcdcd
java: utility
adjabaev Aug 21, 2024
b53ea74
rust: fix signatures
adjabaev Aug 21, 2024
a0dab92
rust-java: remove Taffy from classes & change signatures
adjabaev Aug 21, 2024
d778ff2
enums: enum generator (just to collect feedback)
adjabaev Aug 26, 2024
6d1beb2
enums: fix index parameter as we can get it with ordinal()
adjabaev Aug 26, 2024
71064b0
enums: write files to enum folder
adjabaev Aug 26, 2024
32865ee
enums: use autogenerated files
adjabaev Aug 26, 2024
1fd2c5b
enums: update refs
adjabaev Aug 27, 2024
8bf25f1
java: readded first example for reference
adjabaev Aug 28, 2024
5bae96d
java: add nested and somewhat tweak toString's
adjabaev Aug 28, 2024
9b412c8
java: gap & related util
adjabaev Aug 28, 2024
cbdb98c
rust: fix enum field stuff
adjabaev Aug 28, 2024
114a279
rust/ java: wip - more complex examples
adjabaev Aug 29, 2024
560fd19
genenums: move to to scripts folder
adjabaev Sep 2, 2024
9db2b69
genenums: auto generate "transformers"
adjabaev Sep 2, 2024
1697115
genenums: fix generics
adjabaev Sep 2, 2024
efebe81
genenums: add subfolders
adjabaev Sep 2, 2024
1735861
genenums: support default & remove usage of HashMap as it doesn't kee…
adjabaev Sep 2, 2024
a10e904
genenums: tweak file end line generation
adjabaev Sep 2, 2024
38b6576
genenums: try to fix rustfmt
adjabaev Sep 2, 2024
d7090fb
genenums: try to fix rustfmt
adjabaev Sep 2, 2024
798a82a
genenums: rustfmt stuff
adjabaev Sep 2, 2024
59a793f
genenums: add note for when intersperse is stabilised
adjabaev Sep 3, 2024
765ccd2
java: working on measure function stuff
adjabaev Sep 3, 2024
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
Prev Previous commit
Next Next commit
genenums: auto generate "transformers"
adjabaev committed Sep 2, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 9db2b69796f40945918af91d38abb0c9dc97c723
341 changes: 135 additions & 206 deletions bindings/java/src/enums.rs
Original file line number Diff line number Diff line change
@@ -1,251 +1,180 @@
use crate::conversions::f_get_value;
use crate::primitives::f_i32_from_primitive;
use jni::objects::{JObject, JValueOwned};
use jni::JNIEnv;
use taffy::{
AlignContent, AlignItems, BoxSizing, Display, FlexDirection, FlexWrap, GridAutoFlow, Overflow, Position, TextAlign,
};

pub fn get_overflow<'local>(env: &mut JNIEnv<'local>, value: JValueOwned<'local>) -> Overflow {
let obj = &value.l().unwrap();
if obj.is_null() {
return Overflow::default();
}
use taffy::TextAlign;
use taffy::BoxSizing;
use taffy::AlignContent;
use taffy::GridAutoFlow;
use taffy::FlexDirection;
use taffy::AbsoluteAxis;
use taffy::AlignItems;
use taffy::FlexWrap;
use taffy::BoxGenerationMode;
use taffy::Display;
use taffy::Overflow;
use taffy::Position;
use crate::traits::FromJavaEnum;

let internal = get_enum_value(env, obj);
impl FromJavaEnum for Position {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/Position;";

match internal {
0 => Overflow::Visible,
1 => Overflow::Clip,
2 => Overflow::Hidden,
_ => Overflow::Scroll,
fn from_ordinal(internal: i32) -> Option<Position> {
Some(match internal {
0 => Position::Relative,
1 => Position::Absolute,
_ => panic!("Invalid value: {internal}"),
})
}
}

#[allow(dead_code)]
pub fn f_get_overflow<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> Overflow {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/Overflow;");

get_overflow(env, obj)
}

pub fn get_position<'local>(env: &mut JNIEnv<'local>, value: JValueOwned<'local>) -> Position {
let obj = &value.l().unwrap();
if obj.is_null() {
return Position::default();
}

let internal = get_enum_value(env, obj);
impl FromJavaEnum for Overflow {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/Overflow;";

match internal {
0 => Position::Relative,
_ => Position::Absolute,
fn from_ordinal(internal: i32) -> Option<Overflow> {
Some(match internal {
0 => Overflow::Visible,
1 => Overflow::Clip,
2 => Overflow::Hidden,
3 => Overflow::Scroll,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_position<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> Position {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/Position;");
impl FromJavaEnum for Display {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/Display;";

get_position(env, obj)
}

pub fn get_text_align<'local>(
env: &mut JNIEnv<'local>,
value: JValueOwned<'local>,
def: fn() -> TextAlign,
) -> TextAlign {
let obj = &value.l().unwrap();
if obj.is_null() {
return def();
}

let internal = get_enum_value(env, obj);

match internal {
0 => TextAlign::Auto,
1 => TextAlign::LegacyLeft,
2 => TextAlign::LegacyRight,
_ => TextAlign::LegacyCenter,
fn from_ordinal(internal: i32) -> Option<Display> {
Some(match internal {
0 => Display::Block,
1 => Display::Flex,
2 => Display::Grid,
3 => Display::None,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_text_align<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> TextAlign {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/TextAlign;");

get_text_align(env, obj, TextAlign::default)
}

pub fn get_flex_direction<'local>(
env: &mut JNIEnv<'local>,
value: JValueOwned<'local>,
def: fn() -> FlexDirection,
) -> FlexDirection {
let obj = &value.l().unwrap();
if obj.is_null() {
return def();
}

let internal = get_enum_value(env, obj);
impl FromJavaEnum for BoxGenerationMode {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/BoxGenerationMode;";

match internal {
0 => FlexDirection::Row,
1 => FlexDirection::Column,
2 => FlexDirection::RowReverse,
_ => FlexDirection::ColumnReverse,
fn from_ordinal(internal: i32) -> Option<BoxGenerationMode> {
Some(match internal {
0 => BoxGenerationMode::Normal,
1 => BoxGenerationMode::None,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_flex_direction<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> FlexDirection {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/FlexDirection;");

get_flex_direction(env, obj, FlexDirection::default)
}

pub fn get_flex_wrap<'local>(env: &mut JNIEnv<'local>, value: JValueOwned<'local>, def: fn() -> FlexWrap) -> FlexWrap {
let obj = &value.l().unwrap();
if obj.is_null() {
return def();
}

let internal = get_enum_value(env, obj);
impl FromJavaEnum for FlexWrap {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/FlexWrap;";

match internal {
0 => FlexWrap::NoWrap,
1 => FlexWrap::Wrap,
_ => FlexWrap::WrapReverse,
fn from_ordinal(internal: i32) -> Option<FlexWrap> {
Some(match internal {
0 => FlexWrap::NoWrap,
1 => FlexWrap::Wrap,
2 => FlexWrap::WrapReverse,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_flex_wrap<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> FlexWrap {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/FlexWrap;");
impl FromJavaEnum for AlignItems {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/AlignItems;";

get_flex_wrap(env, obj, FlexWrap::default)
}

pub fn get_grid_auto_flow<'local>(
env: &mut JNIEnv<'local>,
value: JValueOwned<'local>,
def: fn() -> GridAutoFlow,
) -> GridAutoFlow {
let obj = &value.l().unwrap();
if obj.is_null() {
return def();
fn from_ordinal(internal: i32) -> Option<AlignItems> {
Some(match internal {
0 => AlignItems::Start,
1 => AlignItems::End,
2 => AlignItems::FlexStart,
3 => AlignItems::FlexEnd,
4 => AlignItems::Center,
5 => AlignItems::Baseline,
6 => AlignItems::Stretch,
_ => panic!("Invalid value: {internal}"),
})
}

let internal = get_enum_value(env, obj);

match internal {
0 => GridAutoFlow::Row,
1 => GridAutoFlow::Column,
2 => GridAutoFlow::RowDense,
_ => GridAutoFlow::ColumnDense,
}
}

pub fn f_get_grid_auto_flow<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> GridAutoFlow {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/GridAutoFlow;");

get_grid_auto_flow(env, obj, GridAutoFlow::default)
}

pub fn get_align_items<'local>(env: &mut JNIEnv<'local>, value: JValueOwned<'local>) -> Option<AlignItems> {
let obj = &value.l().unwrap();
if obj.is_null() {
return None;
}

let internal = get_enum_value(env, obj);
impl FromJavaEnum for AbsoluteAxis {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/AbsoluteAxis;";

match internal {
0 => Some(AlignItems::Start),
1 => Some(AlignItems::End),
2 => Some(AlignItems::FlexStart),
3 => Some(AlignItems::FlexEnd),
4 => Some(AlignItems::Center),
5 => Some(AlignItems::Baseline),
_ => Some(AlignItems::Stretch),
fn from_ordinal(internal: i32) -> Option<AbsoluteAxis> {
Some(match internal {
0 => AbsoluteAxis::Horizontal,
1 => AbsoluteAxis::Vertical,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_align_items<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> Option<AlignItems> {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/AlignItems;");

get_align_items(env, obj)
}

pub fn get_align_content<'local>(env: &mut JNIEnv<'local>, value: JValueOwned<'local>) -> Option<AlignContent> {
let obj = &value.l().unwrap();
if obj.is_null() {
return None;
}
impl FromJavaEnum for FlexDirection {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/FlexDirection;";

let internal = get_enum_value(env, obj);

match internal {
0 => Some(AlignContent::Start),
1 => Some(AlignContent::End),
2 => Some(AlignContent::FlexStart),
3 => Some(AlignContent::FlexEnd),
4 => Some(AlignContent::Center),
5 => Some(AlignContent::Stretch),
6 => Some(AlignContent::SpaceBetween),
7 => Some(AlignContent::SpaceEvenly),
_ => Some(AlignContent::SpaceAround),
fn from_ordinal(internal: i32) -> Option<FlexDirection> {
Some(match internal {
0 => FlexDirection::Row,
1 => FlexDirection::Column,
2 => FlexDirection::RowReverse,
3 => FlexDirection::ColumnReverse,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_align_content<'local>(
env: &mut JNIEnv<'local>,
base: &JObject<'local>,
field: &str,
) -> Option<AlignContent> {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/AlignContent;");
impl FromJavaEnum for GridAutoFlow {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/GridAutoFlow;";

get_align_content(env, obj)
}

pub fn get_display<'local>(env: &mut JNIEnv<'local>, value: JValueOwned<'local>) -> Display {
let obj = &value.l().unwrap();
if obj.is_null() {
return Display::default();
}

let internal = get_enum_value(env, obj);

match internal {
0 => Display::Block,
1 => Display::Flex,
2 => Display::Grid,
_ => Display::None,
fn from_ordinal(internal: i32) -> Option<GridAutoFlow> {
Some(match internal {
0 => GridAutoFlow::Row,
1 => GridAutoFlow::Column,
2 => GridAutoFlow::RowDense,
3 => GridAutoFlow::ColumnDense,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_display<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> Display {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/Display;");

get_display(env, obj)
}
impl FromJavaEnum for AlignContent {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/AlignContent;";

pub fn get_box_sizing<'local>(env: &mut JNIEnv<'local>, value: JValueOwned<'local>) -> BoxSizing {
let obj = &value.l().unwrap();
if obj.is_null() {
return BoxSizing::default();
fn from_ordinal(internal: i32) -> Option<AlignContent> {
Some(match internal {
0 => AlignContent::Start,
1 => AlignContent::End,
2 => AlignContent::FlexStart,
3 => AlignContent::FlexEnd,
4 => AlignContent::Center,
5 => AlignContent::Stretch,
6 => AlignContent::SpaceBetween,
7 => AlignContent::SpaceEvenly,
8 => AlignContent::SpaceAround,
_ => panic!("Invalid value: {internal}"),
})
}
}

let internal = get_enum_value(env, obj);
impl FromJavaEnum for BoxSizing {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/BoxSizing;";

match internal {
0 => BoxSizing::BorderBox,
_ => BoxSizing::ContentBox,
fn from_ordinal(internal: i32) -> Option<BoxSizing> {
Some(match internal {
0 => BoxSizing::BorderBox,
1 => BoxSizing::ContentBox,
_ => panic!("Invalid value: {internal}"),
})
}
}

pub fn f_get_box_sizing<'local>(env: &mut JNIEnv<'local>, base: &JObject<'local>, field: &str) -> BoxSizing {
let obj = f_get_value(env, base, field, "Lcom/dioxuslabs/taffy/enums/BoxSizing;");

get_box_sizing(env, obj)
}
impl FromJavaEnum for TextAlign {
const JAVA_CLASS: &'static str = "Lcom/dioxuslabs/taffy/enums/TextAlign;";

fn get_enum_value<'local>(env: &mut JNIEnv<'local>, object: &JObject<'local>) -> i32 {
f_i32_from_primitive(env, object, "ordinal", || 0)
}
fn from_ordinal(internal: i32) -> Option<TextAlign> {
Some(match internal {
0 => TextAlign::Auto,
1 => TextAlign::LegacyLeft,
2 => TextAlign::LegacyRight,
3 => TextAlign::LegacyCenter,
_ => panic!("Invalid value: {internal}"),
})
}
}
1 change: 1 addition & 0 deletions bindings/java/src/lib.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ mod geom;
mod java;
mod measure;
mod primitives;
mod traits;

use crate::collections::get_list;
use crate::conversions::get_style;
30 changes: 30 additions & 0 deletions bindings/java/src/primitives.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::conversions::f_get_value;
use crate::traits::FromJavaEnum;
use jni::objects::{JObject, JValueOwned};
use jni::JNIEnv;
use taffy::NodeId;
@@ -254,3 +255,32 @@ pub fn f_bool_from_primitive<'local>(

bool_from_primitive(env, value, def)
}

/// Enums are here as these are basically represented by integers which are primitives
/// Get enum value T from a JValueOwned (as well as a JNIEnv which is required by JNI)
pub fn get_enum<T: FromJavaEnum + Default>(env: &mut JNIEnv, value: JValueOwned) -> T {
let obj = &value.l().unwrap();
if obj.is_null() {
return T::default();
}

let internal = get_enum_value(env, obj);
T::from_ordinal(internal)
}

/// Get enum value T from a JObject and a field name (as well as a JNIEnv which is required by JNI)
pub fn f_get_enum<'local, T: FromJavaEnum + Default>(
env: &mut JNIEnv<'local>,
base: &JObject<'local>,
field: &str,
) -> T {
let obj = f_get_value(env, base, field, T::JAVA_CLASS);

get_enum(env, obj)
}

/// Internal method that gets the ordinal int
fn get_enum_value<'local>(env: &mut JNIEnv<'local>, object: &JObject<'local>) -> i32 {
f_i32_from_primitive(env, object, "ordinal", || 0)
}
4 changes: 4 additions & 0 deletions bindings/java/src/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub trait FromJavaEnum {
const JAVA_CLASS : &'static str;
fn from_ordinal(ordinal: i32) -> Option<RustType>;
}
61 changes: 56 additions & 5 deletions scripts/genenums/src/main.rs
Original file line number Diff line number Diff line change
@@ -2,8 +2,12 @@ use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
fs::remove_file("./bindings/java/src/enums.rs")
.expect("Error: Unable to remove java/src/enums.rs file");

let mut enums: HashMap<&str, Vec<&str>> = HashMap::new();
enums.insert("Display", vec!["Block", "Flex", "Grid", "None"]);
enums.insert("BoxGenerationMode", vec!["Normal", "None"]);
@@ -22,15 +26,18 @@ fn main() {
enums.insert("AbsoluteAxis", vec!["Horizontal", "Vertical"]);

for (key, value) in enums.into_iter() {
create_enum(key, value);
create_enum(key, &value);
create_transformer(key, &value);
}
}

fn create_enum(name: &str, values: Vec<&str>) {
/// Enum generators
fn create_enum(name: &str, values: &[&str]) {
create_java_enum(name, values);
}

fn create_java_enum(name: &str, values: Vec<&str>) {
fn create_java_enum(name: &str, values: &[&str]) {
use convert_case::{Case, Casing};

let package = "com.dioxuslabs.taffy.enums";
@@ -41,9 +48,16 @@ fn create_java_enum(name: &str, values: Vec<&str>) {
** AUTOGENERATED CLASSES FOR TAFFY **
** This code was automatically generated. Do not edit. **
**********************************************************
*/\n";
*/
";

let mut result = format!(
r"{}package {};
let mut result = format!("{}package {};\n\npublic enum {} {{\n", auto_gen_comment, package, enum_name);
public enum {} {{
",
auto_gen_comment, package, enum_name
);

for value in values.iter() {
result.push_str(" ");
@@ -78,3 +92,40 @@ fn create_java_enum(name: &str, values: Vec<&str>) {
File::create(format!("./bindings/java/java/src/main/java/com/dioxuslabs/taffy/enums/{}.java", enum_name));
file.expect("Error: File not found").write_all(result.as_ref()).expect("Error: Couldn't write to file");
}

/// Transformer generators
fn create_transformer(name: &str, values: &[&str]) {
create_java_tranformer(name, values);
}

fn create_java_tranformer(name: &str, values: &[&str]) {
let mut file_content: String = "use crate::traits::FromJavaEnum;".to_string();

if Path::new("./bindings/java/src/enums.rs").exists() {
file_content = fs::read_to_string(Path::new("./bindings/java/src/enums.rs")).unwrap()
}

let mut enum_values: String = "".to_string();
for (index, value) in values.iter().enumerate() {
enum_values.push_str(format!("\n {index} => {name}::{value},").as_str());
}
enum_values.push_str("\n _ => panic!(\"Invalid value: {internal}\"),");

file_content = format!(
"use taffy::{name};
{file_content}
impl FromJavaEnum for {name} {{
const JAVA_CLASS: &'static str = \"Lcom/dioxuslabs/taffy/enums/{name};\";
fn from_ordinal(internal: i32) -> Option<{name}> {{
Some(match internal {{{enum_values}
}})
}}
}}"
);

let file = File::create("./bindings/java/src/enums.rs");
file.expect("Error: File not found").write_all(file_content.as_ref()).expect("Error: Couldn't write to file");
}