Skip to content

Commit fd629c7

Browse files
authored
Add CDC text formatting APIs (#183)
* Add CDC text formatting APIs * Add integer number format factories * Fix text format position handling
1 parent f87e410 commit fd629c7

17 files changed

Lines changed: 3340 additions & 1 deletion

java_runtime/src/classes/java.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod io;
22
pub mod lang;
33
pub mod net;
4+
pub mod text;
45
pub mod util;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
mod date_format;
2+
mod decimal_format;
3+
mod field_position;
4+
mod format;
5+
mod number_format;
6+
mod parse_exception;
7+
mod parse_position;
8+
mod simple_date_format;
9+
10+
pub use self::{
11+
date_format::DateFormat, decimal_format::DecimalFormat, field_position::FieldPosition, format::Format, number_format::NumberFormat,
12+
parse_exception::ParseException, parse_position::ParsePosition, simple_date_format::SimpleDateFormat,
13+
};

java_runtime/src/classes/java/text/date_format.rs

Lines changed: 580 additions & 0 deletions
Large diffs are not rendered by default.

java_runtime/src/classes/java/text/decimal_format.rs

Lines changed: 562 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use alloc::{format, vec};
2+
3+
use java_class_proto::{JavaFieldProto, JavaMethodProto};
4+
use java_constants::{ClassAccessFlags, FieldAccessFlags, MethodAccessFlags};
5+
use jvm::{ClassInstanceRef, Jvm, Result, runtime::JavaLangString};
6+
7+
use crate::{
8+
RuntimeClassProto, RuntimeContext,
9+
classes::java::lang::{Object, String},
10+
};
11+
12+
// public class java.text.FieldPosition
13+
pub struct FieldPosition;
14+
15+
impl FieldPosition {
16+
pub fn as_proto() -> RuntimeClassProto {
17+
RuntimeClassProto {
18+
name: "java/text/FieldPosition",
19+
parent_class: Some("java/lang/Object"),
20+
interfaces: vec![],
21+
methods: vec![
22+
JavaMethodProto::new("<init>", "(I)V", Self::init, MethodAccessFlags::PUBLIC),
23+
JavaMethodProto::new("getField", "()I", Self::get_field, MethodAccessFlags::PUBLIC),
24+
JavaMethodProto::new("getBeginIndex", "()I", Self::get_begin_index, MethodAccessFlags::PUBLIC),
25+
JavaMethodProto::new("getEndIndex", "()I", Self::get_end_index, MethodAccessFlags::PUBLIC),
26+
JavaMethodProto::new("setBeginIndex", "(I)V", Self::set_begin_index, MethodAccessFlags::PUBLIC),
27+
JavaMethodProto::new("setEndIndex", "(I)V", Self::set_end_index, MethodAccessFlags::PUBLIC),
28+
JavaMethodProto::new("equals", "(Ljava/lang/Object;)Z", Self::equals, MethodAccessFlags::PUBLIC),
29+
JavaMethodProto::new("hashCode", "()I", Self::hash_code, MethodAccessFlags::PUBLIC),
30+
JavaMethodProto::new("toString", "()Ljava/lang/String;", Self::to_string, MethodAccessFlags::PUBLIC),
31+
],
32+
fields: vec![
33+
JavaFieldProto::new("field", "I", FieldAccessFlags::PRIVATE),
34+
JavaFieldProto::new("beginIndex", "I", FieldAccessFlags::PRIVATE),
35+
JavaFieldProto::new("endIndex", "I", FieldAccessFlags::PRIVATE),
36+
],
37+
access_flags: ClassAccessFlags::PUBLIC,
38+
}
39+
}
40+
41+
async fn init(jvm: &Jvm, _: &mut RuntimeContext, mut this: ClassInstanceRef<Self>, field: i32) -> Result<()> {
42+
let _: () = jvm.invoke_special(&this, "java/lang/Object", "<init>", "()V", ()).await?;
43+
jvm.put_field(&mut this, "field", "I", field).await?;
44+
jvm.put_field(&mut this, "beginIndex", "I", 0).await?;
45+
jvm.put_field(&mut this, "endIndex", "I", 0).await
46+
}
47+
48+
async fn get_field(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
49+
jvm.get_field(&this, "field", "I").await
50+
}
51+
52+
async fn get_begin_index(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
53+
jvm.get_field(&this, "beginIndex", "I").await
54+
}
55+
56+
async fn get_end_index(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
57+
jvm.get_field(&this, "endIndex", "I").await
58+
}
59+
60+
async fn set_begin_index(jvm: &Jvm, _: &mut RuntimeContext, mut this: ClassInstanceRef<Self>, value: i32) -> Result<()> {
61+
jvm.put_field(&mut this, "beginIndex", "I", value).await
62+
}
63+
64+
async fn set_end_index(jvm: &Jvm, _: &mut RuntimeContext, mut this: ClassInstanceRef<Self>, value: i32) -> Result<()> {
65+
jvm.put_field(&mut this, "endIndex", "I", value).await
66+
}
67+
68+
async fn equals(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, other: ClassInstanceRef<Object>) -> Result<bool> {
69+
if other.is_null() || !jvm.is_instance(&**other, "java/text/FieldPosition") {
70+
return Ok(false);
71+
}
72+
73+
let other: ClassInstanceRef<Self> = ClassInstanceRef::new(other.instance);
74+
let field: i32 = jvm.get_field(&this, "field", "I").await?;
75+
let other_field: i32 = jvm.get_field(&other, "field", "I").await?;
76+
let begin_index: i32 = jvm.get_field(&this, "beginIndex", "I").await?;
77+
let other_begin_index: i32 = jvm.get_field(&other, "beginIndex", "I").await?;
78+
let end_index: i32 = jvm.get_field(&this, "endIndex", "I").await?;
79+
let other_end_index: i32 = jvm.get_field(&other, "endIndex", "I").await?;
80+
Ok(field == other_field && begin_index == other_begin_index && end_index == other_end_index)
81+
}
82+
83+
async fn hash_code(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
84+
let field: i32 = jvm.get_field(&this, "field", "I").await?;
85+
let begin_index: i32 = jvm.get_field(&this, "beginIndex", "I").await?;
86+
let end_index: i32 = jvm.get_field(&this, "endIndex", "I").await?;
87+
Ok(field ^ begin_index.rotate_left(11) ^ end_index.rotate_left(22))
88+
}
89+
90+
async fn to_string(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<String>> {
91+
let field: i32 = jvm.get_field(&this, "field", "I").await?;
92+
let begin_index: i32 = jvm.get_field(&this, "beginIndex", "I").await?;
93+
let end_index: i32 = jvm.get_field(&this, "endIndex", "I").await?;
94+
Ok(JavaLangString::from_rust_string(
95+
jvm,
96+
&format!("java.text.FieldPosition[field={field},beginIndex={begin_index},endIndex={end_index}]"),
97+
)
98+
.await?
99+
.into())
100+
}
101+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use alloc::vec;
2+
3+
use java_class_proto::JavaMethodProto;
4+
use java_constants::{ClassAccessFlags, MethodAccessFlags};
5+
use jvm::{ClassInstanceRef, JavaError, Jvm, Result, runtime::JavaLangString};
6+
7+
use crate::{
8+
RuntimeClassProto, RuntimeContext,
9+
classes::java::{
10+
lang::{Object, String, StringBuffer},
11+
text::{FieldPosition, ParseException, ParsePosition},
12+
},
13+
};
14+
15+
// public abstract class java.text.Format
16+
pub struct Format;
17+
18+
impl Format {
19+
pub fn as_proto() -> RuntimeClassProto {
20+
RuntimeClassProto {
21+
name: "java/text/Format",
22+
parent_class: Some("java/lang/Object"),
23+
interfaces: vec!["java/io/Serializable", "java/lang/Cloneable"],
24+
methods: vec![
25+
JavaMethodProto::new("<init>", "()V", Self::init, MethodAccessFlags::PROTECTED),
26+
JavaMethodProto::new(
27+
"format",
28+
"(Ljava/lang/Object;)Ljava/lang/String;",
29+
Self::format,
30+
MethodAccessFlags::PUBLIC | MethodAccessFlags::FINAL,
31+
),
32+
JavaMethodProto::new_abstract(
33+
"format",
34+
"(Ljava/lang/Object;Ljava/lang/StringBuffer;Ljava/text/FieldPosition;)Ljava/lang/StringBuffer;",
35+
MethodAccessFlags::PUBLIC | MethodAccessFlags::ABSTRACT,
36+
),
37+
JavaMethodProto::new(
38+
"parseObject",
39+
"(Ljava/lang/String;)Ljava/lang/Object;",
40+
Self::parse_object,
41+
MethodAccessFlags::PUBLIC,
42+
),
43+
JavaMethodProto::new_abstract(
44+
"parseObject",
45+
"(Ljava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Object;",
46+
MethodAccessFlags::PUBLIC | MethodAccessFlags::ABSTRACT,
47+
),
48+
JavaMethodProto::new("clone", "()Ljava/lang/Object;", Self::clone, MethodAccessFlags::PUBLIC),
49+
],
50+
fields: vec![],
51+
access_flags: ClassAccessFlags::PUBLIC | ClassAccessFlags::ABSTRACT,
52+
}
53+
}
54+
55+
async fn init(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
56+
jvm.invoke_special(&this, "java/lang/Object", "<init>", "()V", ()).await
57+
}
58+
59+
async fn format(
60+
jvm: &Jvm,
61+
_: &mut RuntimeContext,
62+
this: ClassInstanceRef<Self>,
63+
object: ClassInstanceRef<Object>,
64+
) -> Result<ClassInstanceRef<String>> {
65+
let buffer: ClassInstanceRef<StringBuffer> = jvm.new_class("java/lang/StringBuffer", "()V", ()).await?.into();
66+
let position: ClassInstanceRef<FieldPosition> = jvm.new_class("java/text/FieldPosition", "(I)V", (0,)).await?.into();
67+
let buffer: ClassInstanceRef<StringBuffer> = jvm
68+
.invoke_virtual(
69+
&this,
70+
"format",
71+
"(Ljava/lang/Object;Ljava/lang/StringBuffer;Ljava/text/FieldPosition;)Ljava/lang/StringBuffer;",
72+
(object, buffer, position),
73+
)
74+
.await?;
75+
jvm.invoke_virtual(&buffer, "toString", "()Ljava/lang/String;", ()).await
76+
}
77+
78+
async fn parse_object(
79+
jvm: &Jvm,
80+
_: &mut RuntimeContext,
81+
this: ClassInstanceRef<Self>,
82+
source: ClassInstanceRef<String>,
83+
) -> Result<ClassInstanceRef<Object>> {
84+
if source.is_null() {
85+
return Err(jvm.exception("java/lang/NullPointerException", "source").await);
86+
}
87+
88+
let position: ClassInstanceRef<ParsePosition> = jvm.new_class("java/text/ParsePosition", "(I)V", (0,)).await?.into();
89+
let result: ClassInstanceRef<Object> = jvm
90+
.invoke_virtual(
91+
&this,
92+
"parseObject",
93+
"(Ljava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Object;",
94+
(source, position.clone()),
95+
)
96+
.await?;
97+
let index: i32 = jvm.invoke_virtual(&position, "getIndex", "()I", ()).await?;
98+
if index == 0 {
99+
let error_index: i32 = jvm.invoke_virtual(&position, "getErrorIndex", "()I", ()).await?;
100+
let message = JavaLangString::from_rust_string(jvm, "Format.parseObject(String) failed").await?;
101+
let exception: ClassInstanceRef<ParseException> = jvm
102+
.new_class("java/text/ParseException", "(Ljava/lang/String;I)V", (message, error_index))
103+
.await?
104+
.into();
105+
return Err(JavaError::JavaException(exception.into()));
106+
}
107+
Ok(result)
108+
}
109+
110+
async fn clone(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Object>> {
111+
Ok(jvm.shallow_clone(&this)?.into())
112+
}
113+
}

0 commit comments

Comments
 (0)