diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/rust/Native.java b/eo-maven-plugin/src/main/java/org/eolang/maven/rust/Native.java index 0a6c7a9527..24c34a239f 100644 --- a/eo-maven-plugin/src/main/java/org/eolang/maven/rust/Native.java +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/rust/Native.java @@ -75,7 +75,7 @@ public void save(final Footprint footprint) throws IOException { this.name ), String.format( - " public static native int %s", + " public static native byte[] %s", this.name ), " (final EOrust eo);", diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/rust/PrimeModule.java b/eo-maven-plugin/src/main/java/org/eolang/maven/rust/PrimeModule.java index 5902888377..63a566547b 100644 --- a/eo-maven-plugin/src/main/java/org/eolang/maven/rust/PrimeModule.java +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/rust/PrimeModule.java @@ -42,14 +42,15 @@ public PrimeModule(final String method, final String file) { "mod foo;", "use foo::foo;", "use jni::JNIEnv;", - "use jni::objects::{JClass, JObject};", - "use jni::sys::{jint};", + "use jni::objects::{JByteArray, JClass, JObject};", "use eo_env::EOEnv;", "#[no_mangle]", "pub extern \"system\" fn", String.format("Java_EOrust_natives_%s_%s", method, method), - "<'local> (env: JNIEnv<'local>, _class: JClass<'local>, universe: JObject<'local>) -> jint", - "{ return foo(EOEnv::new(env, _class, universe)); }" + "<'local> (env: JNIEnv<'local>, _class: JClass<'local>, universe: JObject<'local>) -> JByteArray<'local>", + "{ let mut eo_env = EOEnv::new(env, _class, universe); ", + "let arr = foo(&mut eo_env).eo2vec();", + "eo_env.java_env.byte_array_from_slice(&arr.as_slice()).unwrap() }" ), file ); diff --git a/eo-maven-plugin/src/test/java/org/eolang/maven/BinarizeParseMojoTest.java b/eo-maven-plugin/src/test/java/org/eolang/maven/BinarizeParseMojoTest.java index c47ed5b81a..572aff8429 100644 --- a/eo-maven-plugin/src/test/java/org/eolang/maven/BinarizeParseMojoTest.java +++ b/eo-maven-plugin/src/test/java/org/eolang/maven/BinarizeParseMojoTest.java @@ -24,7 +24,6 @@ package org.eolang.maven; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Map; import org.cactoos.text.TextOf; import org.eolang.jucs.ClasspathSource; @@ -71,11 +70,11 @@ void parsesSimpleEoProgram(@TempDir final Path temp) throws Exception { new TextOf(res.get(rust)).asString(), Matchers.stringContainsInOrder( "use rand::Rng;", - "pub fn foo(mut env: EOEnv<'_>) -> i32 {", + "pub fn foo(_env: &EOEnv) -> EO {", " let mut rng = rand::thread_rng();", " print!(\"Hello world\");", - " let i = rng.gen::();", - " i", + " let i = rng.gen::();", + " EOInt(i)", "}" ) ); @@ -88,13 +87,13 @@ void parsesSimpleEoProgram(@TempDir final Path temp) throws Exception { ) ) ).asString(), - Matchers.containsString("public static native int") + Matchers.containsString("public static native byte[]") ); } @Test void binarizesTwiceRustProgram(@TempDir final Path temp) throws Exception { - final Path src = Paths.get("src/test/resources/org/eolang/maven/binarize/twice-rust.eo"); + final Path src = BinarizeMojoTest.SRC.resolve("twice-rust.eo"); final FakeMaven maven; synchronized (BinarizeParseMojoTest.class) { maven = new FakeMaven(temp).withProgram(src); @@ -119,14 +118,18 @@ void binarizesTwiceRustProgram(@TempDir final Path temp) throws Exception { MatcherAssert.assertThat( new TextOf(res.get(one)).asString(), Matchers.stringContainsInOrder( - "pub fn foo(mut _env: EOEnv<'_>) -> i32 {", + "use eo_env::eo_enum::EO;", + "use eo_env::eo_enum::EO::{EOInt};", + "pub fn foo(_env: &EOEnv) -> EO {", "println!(\"{}\", x);" ) ); MatcherAssert.assertThat( new TextOf(res.get(two)).asString(), Matchers.stringContainsInOrder( - "pub fn foo(mut _env: EOEnv<'_>) -> i32 {", + "use eo_env::eo_enum::EO;", + "use eo_env::eo_enum::EO::{EOInt};", + "pub fn foo(_env: &EOEnv) -> EO {", "print!(\"Hello 大 2\");" ) ); diff --git a/eo-maven-plugin/src/test/java/org/eolang/maven/FakeMaven.java b/eo-maven-plugin/src/test/java/org/eolang/maven/FakeMaven.java index b70c8bcca5..716e7e58de 100644 --- a/eo-maven-plugin/src/test/java/org/eolang/maven/FakeMaven.java +++ b/eo-maven-plugin/src/test/java/org/eolang/maven/FakeMaven.java @@ -232,7 +232,7 @@ public FakeMaven execute(final Class mojo) throws IO this.params.putIfAbsent("objectionary", new Objectionary.Fake()); this.params.putIfAbsent( "eoEnvDir", - new File("src/test/resources/org/eolang/maven/binarize/eo_env") + new File("../eo-runtime/src/main/rust/eo_env") ); } final Moja moja = new Moja<>(mojo); diff --git a/eo-maven-plugin/src/test/java/org/eolang/maven/rust/NativeTest.java b/eo-maven-plugin/src/test/java/org/eolang/maven/rust/NativeTest.java index c451847d44..771ddd2e37 100644 --- a/eo-maven-plugin/src/test/java/org/eolang/maven/rust/NativeTest.java +++ b/eo-maven-plugin/src/test/java/org/eolang/maven/rust/NativeTest.java @@ -52,7 +52,7 @@ void savesCorrectly(@TempDir final Path temp) throws Exception { "package mypackage;", "import EOorg.EOeolang.EOrust;", "public class name {", - " public static native int name", + " public static native byte[] name", " (final EOrust eo);", "}" ) diff --git a/eo-maven-plugin/src/test/java/org/eolang/maven/rust/PrimeModuleTest.java b/eo-maven-plugin/src/test/java/org/eolang/maven/rust/PrimeModuleTest.java index 8a39b1134b..9355f12673 100644 --- a/eo-maven-plugin/src/test/java/org/eolang/maven/rust/PrimeModuleTest.java +++ b/eo-maven-plugin/src/test/java/org/eolang/maven/rust/PrimeModuleTest.java @@ -49,7 +49,7 @@ void savesCorrectly(@TempDir final Path temp) throws Exception { ).asString(), Matchers.stringContainsInOrder( String.format("Java_EOrust_natives_%s_%s", method, method), - "<'local> (env: JNIEnv<'local>, _class: JClass<'local>, universe: JObject<'local>) -> jint" + "<'local> (env: JNIEnv<'local>, _class: JClass<'local>, universe: JObject<'local>) -> JByteArray" ) ); } diff --git a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/eo_env/Cargo.toml b/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/eo_env/Cargo.toml deleted file mode 100644 index d7f29f7e3a..0000000000 --- a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/eo_env/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "eo_env" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -jni = "0.21.1" - -[lib] -path = "src/eo_env.rs" \ No newline at end of file diff --git a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/eo_env/src/eo_env.rs b/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/eo_env/src/eo_env.rs deleted file mode 100644 index 7361d82ff6..0000000000 --- a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/eo_env/src/eo_env.rs +++ /dev/null @@ -1,19 +0,0 @@ -use jni::JNIEnv; -use jni::objects::{JClass, JObject}; - -#[allow(dead_code)] -pub struct EOEnv<'local> { - java_env: JNIEnv<'local>, - java_class: JClass<'local>, - java_obj: JObject<'local> -} - -impl<'local> EOEnv<'_> { - pub fn new(java_env: JNIEnv<'local>, java_class: JClass<'local>, java_obj: JObject<'local>) -> EOEnv<'local> { - EOEnv { - java_env, - java_class, - java_obj - } - } -} diff --git a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/simple-rust.eo b/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/simple-rust.eo index c8ae6abbaa..305dc3cd05 100644 --- a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/simple-rust.eo +++ b/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/simple-rust.eo @@ -6,12 +6,14 @@ """ use rand::Rng; use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; - pub fn foo(mut env: EOEnv<'_>) -> i32 { + pub fn foo(_env: &EOEnv) -> EO { let mut rng = rand::thread_rng(); print!("Hello world"); - let i = rng.gen::(); - i + let i = rng.gen::(); + EOInt(i) } """ * diff --git a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/twice-rust.eo b/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/twice-rust.eo index e5ddaff396..35528a1a6b 100644 --- a/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/twice-rust.eo +++ b/eo-maven-plugin/src/test/resources/org/eolang/maven/binarize/twice-rust.eo @@ -5,11 +5,13 @@ QQ.rust > r """ use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; - pub fn foo(mut _env: EOEnv<'_>) -> i32 { + pub fn foo(_env: &EOEnv) -> EO { let x = rand::random::(); println!("{}", x); - x + EOInt(x as i64) } """ * @@ -20,11 +22,13 @@ QQ.rust > r """ use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; - pub fn foo(mut _env: EOEnv<'_>) -> i32 { + pub fn foo(_env: &EOEnv) -> EO { print!("Hello 大 2"); let x = rand::random::(); - x + EOInt(x as i64) } """ * diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOrust.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOrust.java index 1c6d211ab1..66ad9fd061 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EOrust.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOrust.java @@ -32,8 +32,10 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.lang.reflect.Method; +import java.nio.ByteBuffer; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.SystemUtils; @@ -56,6 +58,10 @@ * @checkstyle MethodNameCheck (100 lines) * @checkstyle LineLengthCheck (100 lines) * @checkstyle TypeNameCheck (5 lines) + * @todo #2283:90min Create Universe class. Now its functionality is + * assigned to "EORust", which is why it is overcomplicated. "Universe" + * should perform a model of interaction with "eo" objects through + * methods "find", "put", "copy", "dataize" and "bind". */ @XmirObject(oname = "rust") public class EOrust extends PhDefault { @@ -128,9 +134,17 @@ public EOrust(final Phi sigma) { "EOrust.natives.%s", name ) - ).getDeclaredMethod(name, new Class[]{EOrust.class}); - return new Data.ToPhi( - Long.valueOf((int) method.invoke(null, this)) + ).getDeclaredMethod(name, EOrust.class); + if (method.getReturnType() != byte[].class) { + throw new ExFailure( + "Return type of %s is %s, required %s", + method, + method.getReturnType(), + byte[].class + ); + } + return EOrust.translate( + (byte[]) method.invoke(null, this) ); } ) @@ -228,4 +242,44 @@ private static ConcurrentHashMap load(final String src) throws I ); } } + + /** + * Translates byte message from rust side to Phi object. + * @param message Message that native method returns. + * @return Phi object. + * @todo #2283:45min Implement handling of vertex returning. + * It must convert message array from 1 to last byte to the int + * and return eo object with corresponding vertex then. + * @todo #2283:45min Implement handling of String returning. + * It must convert message array from 1 to last byte to the String + * and return eo object with converted String Data. + */ + private static Phi translate(final byte[] message) { + final byte determinant = message[0]; + final byte[] content = Arrays.copyOfRange(message, 1, message.length); + final Phi ret; + switch (determinant) { + case 0: + throw new ExFailure( + "Returning vertex is not implemented yet" + ); + case 1: + ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES); + buffer.put(content); + buffer.flip(); + ret = new Data.ToPhi(buffer.getDouble()); + break; + case 2: + buffer = ByteBuffer.allocate(Long.BYTES); + buffer.put(content); + buffer.flip(); + ret = new Data.ToPhi(buffer.getLong()); + break; + default: + throw new ExFailure( + "Returning Strings and raw bytes is not implemented yet" + ); + } + return ret; + } } diff --git a/eo-runtime/src/main/rust/eo_env/src/eo_enum.rs b/eo-runtime/src/main/rust/eo_env/src/eo_enum.rs new file mode 100644 index 0000000000..4929c7aca0 --- /dev/null +++ b/eo-runtime/src/main/rust/eo_env/src/eo_enum.rs @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2023 Objectionary.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +pub enum EO { + EOVertex(u32), + EOFloat(f64), + EOInt(i64), + EOString(String), + EORaw(Box<[u8]>), +} + +impl EO { + pub fn eo2vec(&self) -> Vec { + match self { + EO::EOVertex(v) => { + let mut res: Vec = vec![0; 1 + 4]; + res[0] = 0; + res[1..].copy_from_slice(&v.to_le_bytes()); + res + } + EO::EOFloat(x) => { + let mut res = vec![0; 1 + 8]; + res[0] = 1; + res[1..].copy_from_slice(&x.to_be_bytes()); + res + } + EO::EOInt(x) => { + let mut res: Vec = vec![0; 1 + 8]; + res[0] = 2; + res[1..].copy_from_slice(&x.to_be_bytes()); + res + } + EO::EOString(_) => { vec![0xff] } + EO::EORaw(_) => { vec![0xff] } + } + } +} diff --git a/eo-runtime/src/main/rust/eo_env/src/eo_env.rs b/eo-runtime/src/main/rust/eo_env/src/eo_env.rs index 29af75cda2..3c6793a980 100644 --- a/eo-runtime/src/main/rust/eo_env/src/eo_env.rs +++ b/eo-runtime/src/main/rust/eo_env/src/eo_env.rs @@ -1,18 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2023 Objectionary.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +pub mod eo_enum; use jni::JNIEnv; use jni::objects::{JClass, JObject, JValue}; -#[allow(dead_code)] pub struct EOEnv<'local> { - java_env: JNIEnv<'local>, - java_class: JClass<'local>, + pub java_env: JNIEnv<'local>, + _java_class: JClass<'local>, java_obj: JObject<'local> } impl<'local> EOEnv<'_> { - pub fn new(java_env: JNIEnv<'local>, java_class: JClass<'local>, java_obj: JObject<'local>) -> EOEnv<'local> { + pub fn new(java_env: JNIEnv<'local>, _java_class: JClass<'local>, java_obj: JObject<'local>) -> EOEnv<'local> { EOEnv { java_env, - java_class, + _java_class, java_obj } } @@ -79,6 +103,7 @@ impl<'local> EOEnv<'_> { * call java dataizing method and get byte array from it. * Then it have to return byte array as a result of dataization. */ + #[allow(unused_variables)] pub fn dataize(&mut self, v: u32) -> Option<&[u32]> { Some(&[0x0]) } diff --git a/eo-runtime/src/test/eo/org/eolang/rust-tests.eo b/eo-runtime/src/test/eo/org/eolang/rust-tests.eo index 0faa9eaa10..469990bfd0 100644 --- a/eo-runtime/src/test/eo/org/eolang/rust-tests.eo +++ b/eo-runtime/src/test/eo/org/eolang/rust-tests.eo @@ -26,15 +26,16 @@ +package org.eolang +version 0.0.0 -[] > rust-creates-object +[] > rust-returns-positive-int QQ.rust > r """ use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; - pub fn foo(mut _env: EOEnv<'_>) -> i32 { + pub fn foo(_env: &mut EOEnv) -> EO { println!("Hello world from rust"); - let x = 4.0_f32; - x.sqrt() as i32 + EOInt(2) } """ * @@ -43,30 +44,85 @@ $.equal-to 2 -[] > rust-find-returns-int +[] > rust-returns-negative-int QQ.rust > r """ use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; - pub fn foo(mut env: EOEnv<'_>) -> i32 { - env.find("^"); - 0 + pub fn foo(_env: &mut EOEnv) -> EO { + println!("Hello world from rust"); + EOInt(-10) } """ * assert-that > @ r $.equal-to - 0 + -10 -[] > rust-put-not-fails +[] > rust-returns-positive-doable + QQ.rust > r + """ + use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOFloat}; + + pub fn foo(_env: &mut EOEnv) -> EO { + EOFloat(1.23456789) + } + """ + * + assert-that > @ + r + $.equal-to + 1.23456789 + +[] > rust-returns-negative-doable QQ.rust > r """ use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOFloat}; - pub fn foo(mut env: EOEnv<'_>) -> i32 { + pub fn foo(_env: &mut EOEnv) -> EO { + EOFloat(-1.23456789) + } + """ + * + assert-that > @ + r + $.equal-to + -1.23456789 + +[] > rust-find-returns-int + QQ.rust > r + """ + use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; + + pub fn foo(env: &mut EOEnv) -> EO { + EOInt(env.find("^").into()) + } + """ + * + assert-that > @ + r + $.not + $.less-than + 0 + +[] > rust-put-not-fails + QQ.rust > r + """ + use eo_env::EOEnv; + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; + pub fn foo(env: &mut EOEnv) -> EO { env.put(3, &[0x00, 0x1a, 0xEE, 0xf, 0xf3]).unwrap(); - 0 + EOInt(0 as i64) } """ * @@ -80,11 +136,13 @@ QQ.rust > insert """ use eo_env::EOEnv; - pub fn foo(mut env: EOEnv<'_>) -> i32 { + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; + pub fn foo(env: &mut EOEnv) -> EO { let v1 = env.find("a") as u32; let v2 = env.find("b") as u32; - env.bind(v1 , v2, "my-att"); - return v1 as i32; + env.bind(v1 , v2, "EO-att"); + return EOInt(v1 as i64); } """ * @@ -98,10 +156,12 @@ QQ.rust > copy """ use eo_env::EOEnv; - pub fn foo(mut env: EOEnv<'_>) -> i32 { + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; + pub fn foo(env: &mut EOEnv) -> EO { let v = env.find("a") as u32; let copy = env.copy(v).unwrap(); - copy as i32 + EOInt(copy as i64) } """ * @@ -115,10 +175,12 @@ QQ.rust > dataized """ use eo_env::EOEnv; - pub fn foo(mut env: EOEnv<'_>) -> i32 { + use eo_env::eo_enum::EO; + use eo_env::eo_enum::EO::{EOInt}; + pub fn foo(env: &mut EOEnv) -> EO { let v = env.find("a") as u32; - let bytes = env.dataize(v).unwrap(); - v as i32 + let _bytes = env.dataize(v).unwrap(); + EOInt(v as i64) } """ *