Skip to content

Commit d77dc55

Browse files
committed
New test - binary search
1 parent ccf5526 commit d77dc55

File tree

12 files changed

+113
-20
lines changed

12 files changed

+113
-20
lines changed

Readme.md

+12-12
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ Compile your Rust code into a runnable `.jar` on JVM 8+!
2424
---
2525

2626
## 🔥 Demos
27-
28-
All examples live in `tests/binary` and are compiled to JVM bytecode & run/tested on the CI on every commit. Some exicting demos made in pure-Rust include:
29-
30-
- **RSA** encryption/decryption (`rsa`)
31-
- **Fibonacci** sequence generator (`fibonacci`)
32-
- **Collatz conjecture** verifier (`collatz`)
33-
- **Large prime** generator (`primes`)
34-
- Nested data structures: enums, structs, tuples, arrays, slices (`enums`, `structs`)
27+
All examples live in `tests/binary` and are compiled to JVM bytecode & run/tested on the CI on every commit. Some exciting demos made in pure-Rust include:
28+
29+
- **[RSA](tests/binary/rsa/src/main.rs)** encryption/decryption
30+
- **[Binary search](tests/binary/binsearch/src/main.rs)** algorithm
31+
- **[Fibonacci](tests/binary/fibonacci/src/main.rs)** sequence generator
32+
- **[Collatz conjecture](tests/binary/collatz/src/main.rs)** verifier
33+
- **[Large prime](tests/binary/primes/src/main.rs)** generator
34+
- Use of nested data structures: enums, structs, tuples, arrays, slices (**[enums](tests/binary/enums/src/main.rs)**, **[structs](tests/binary/structs/src/main.rs)** - both tests use arrays and tuples)
3535
- …and more!
3636

3737
---
@@ -95,7 +95,7 @@ This will compile:
9595
- `rustc_codegen_jvm` backend library
9696
- `java-linker`
9797
- `asm-processor`
98-
- Kotlin shim for `core`
98+
- Kotlin shim for `core` (once core support is reached, this will no longer be needed)
9999
- Generate `config.toml` & `jvm-unknown-unknown.json`
100100

101101
If you relocate the repo, re-run:
@@ -108,17 +108,17 @@ make gen-files
108108
## 🚀 Usage
109109

110110
1. **Configure your project**
111-
In *your* Rust project directory, create or update `.cargo/config.toml` with the generated template.
111+
In *your* Rust project directory, create or update `.cargo/config.toml` with the generated template (will be at the root of this repo after running make).
112112

113113
2. **Build with Cargo**
114114
```bash
115115
cargo build # debug
116-
cargo build --release # optimized
116+
cargo build --release # optimized - functionality available slightly impaired
117117
```
118118

119119
3. **Run the `.jar`**
120120
```bash
121-
java -jar target/debug/deps/your_crate.jar
121+
java -jar target/debug/deps/your_crate*.jar
122122
```
123123

124124
---

library/src/main/kotlin/org/rustlang/core/Core.kt

+25
Original file line numberDiff line numberDiff line change
@@ -219,4 +219,29 @@ public object Core {
219219
}
220220
}
221221

222+
@JvmStatic
223+
// same as unwrap but return true/false if None instead of exception
224+
public fun option_is_none(optionObj: Any?): Boolean {
225+
if (optionObj == null) {
226+
// This shouldn't happen if the codegen is correct, as unwrap is called on an instance.
227+
panic_fmt("FATAL: Called option_is_none on a null reference. This indicates a bug in the code generator.")
228+
// Need a return path for the compiler, even though panic throws.
229+
throw RuntimeException("Unreachable after panic")
230+
}
231+
232+
// Determine the variant using instanceof (Kotlin 'is')
233+
if (optionObj::class.java.name.endsWith("option\$some")) {
234+
// It's Some(value). Return false.
235+
return false
236+
} else if (optionObj::class.java.name.endsWith("option\$none")) {
237+
// It's None. Return true.
238+
return true
239+
} else {
240+
// Input object was not an expected Option variant. This indicates a codegen bug.
241+
val className = optionObj::class.java.name
242+
panic_fmt("Internal Compiler Error: Called option_is_none on an unexpected type: $className. Expected type ending in option\$some or option\$none.")
243+
throw RuntimeException("Unreachable after panic") // For compiler
244+
}
245+
}
246+
222247
}

shim-metadata-gen/core.json

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
"descriptor": "(Ljava/lang/Object;Ljava/lang/Object;)Z",
4444
"is_static": true
4545
},
46+
"option_is_none": {
47+
"descriptor": "(Ljava/lang/Object;)Z",
48+
"is_static": true
49+
},
4650
"option_unwrap": {
4751
"descriptor": "(Ljava/lang/Object;)Ljava/lang/Object;",
4852
"is_static": true

src/lower1/operand.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,22 @@ pub fn handle_const_value<'tcx>(
426426
}
427427
} else {
428428
/* Array element type is not Ref */
429-
println!(
430-
"Warning: Scalar::Ptr points to Ref-to-Array where element type {:?} is not a reference.",
431-
elem_ty
432-
);
433-
return oomir::Operand::Constant(
434-
oomir::Constant::I64(-5),
435-
); // Indicate wrong element type
429+
match read_constant_value_from_memory(tcx, allocation, pointer.into_parts().1, *inner_ty, data_types) {
430+
Ok(oomir_const) => {
431+
println!(
432+
"Info: Successfully read constant value from memory: {:?}",
433+
oomir_const
434+
);
435+
return oomir::Operand::Constant(oomir_const);
436+
}
437+
Err(e) => {
438+
println!(
439+
"Warning: Failed to read constant value from memory for allocation {:?}. Error: {:?}",
440+
alloc_id, e
441+
);
442+
return oomir::Operand::Constant(oomir::Constant::I32(-1))
443+
}
444+
}
436445
}
437446
} else {
438447
// Could not determine array length (e.g., generic)

src/lower1/types.rs

+5
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ pub fn ty_to_oomir_type<'tcx>(
163163
// Default slice handling
164164
oomir::Type::Array(Box::new(ty_to_oomir_type(*component_ty, tcx, data_types)))
165165
}
166+
rustc_middle::ty::TyKind::Never => {
167+
// Handle the never type
168+
println!("Info: Mapping Never type to OOMIR Void");
169+
oomir::Type::Void
170+
}
166171
_ => {
167172
println!("Warning: Unhandled type {:?}", ty);
168173
oomir::Type::Class("UnsupportedType".to_string())

src/lower2/helpers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ pub fn parse_jvm_descriptor_return(descriptor: &str) -> Result<String, String> {
602602
println!("Parsing return type from descriptor: {}", descriptor);
603603

604604
// 1. find the parentheses
605-
let open_paren = descriptor
605+
descriptor
606606
.find('(')
607607
.ok_or_else(|| "Descriptor must start with '('".to_string())?;
608608
let close_paren = descriptor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../config.toml

tests/binary/binsearch/Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/binary/binsearch/Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "binsearch"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]

tests/binary/binsearch/java-output.expected

Whitespace-only changes.

tests/binary/binsearch/no_jvm_target.flag

Whitespace-only changes.

tests/binary/binsearch/src/main.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/// Binary search for u32 slices.
2+
/// Returns `Some(index)` if `target` is found, or `None` otherwise.
3+
pub fn binary_search(slice: &[u32], target: u32) -> Option<usize> {
4+
let mut low = 0;
5+
let mut high = slice.len();
6+
7+
while low < high {
8+
// mid = floor((low + high) / 2) without overflow
9+
let mid = low + (high - low) / 2;
10+
let v = slice[mid];
11+
if v < target {
12+
low = mid + 1;
13+
} else if v > target {
14+
high = mid;
15+
} else {
16+
return Some(mid);
17+
}
18+
}
19+
20+
None
21+
}
22+
23+
fn main() {
24+
// demo array (must be sorted!)
25+
let arr = [1, 2, 3, 5, 8, 13, 21];
26+
27+
// successful searches
28+
assert!(binary_search(&arr, 1) == Some(0));
29+
assert!(binary_search(&arr, 5) == Some(3));
30+
assert!(binary_search(&arr, 21) == Some(6));
31+
32+
// unsuccessful searches
33+
assert!(binary_search(&arr, 0).is_none());
34+
assert!(binary_search(&arr, 4).is_none());
35+
assert!(binary_search(&arr, 22).is_none());
36+
}

0 commit comments

Comments
 (0)