diff --git a/ristretto_classloader/src/object.rs b/ristretto_classloader/src/object.rs index 626e74fd..fed2aeca 100644 --- a/ristretto_classloader/src/object.rs +++ b/ristretto_classloader/src/object.rs @@ -392,7 +392,7 @@ impl Object { /// if the object is not an instance of `java/lang/Byte` or if the value cannot be converted to /// an unsigned byte. pub fn as_u8(&self) -> Result { - let value: i8 = self.as_i8()?; + let value = self.as_i8()?; #[expect(clippy::cast_sign_loss)] Ok(value as u8) } @@ -418,7 +418,7 @@ impl Object { /// if the object is not an instance of `java/lang/Short` or if the value cannot be converted to /// an unsigned short. pub fn as_u16(&self) -> Result { - let value: i16 = self.as_i16()?; + let value = self.as_i16()?; #[expect(clippy::cast_sign_loss)] Ok(value as u16) } @@ -442,7 +442,7 @@ impl Object { /// if the object is not an instance of `java/lang/Integer` or if the value cannot be converted /// to an unsigned integer. pub fn as_u32(&self) -> Result { - let value: i32 = self.as_i32()?; + let value = self.as_i32()?; #[expect(clippy::cast_sign_loss)] Ok(value as u32) } @@ -455,7 +455,7 @@ impl Object { /// a signed long. pub fn as_i64(&self) -> Result { let value = self.class_value("java/lang/Long")?; - let value = value.try_into()?; + let value: i64 = value.try_into()?; Ok(value) } @@ -466,7 +466,7 @@ impl Object { /// if the object is not an instance of `java/lang/Long` or if the value cannot be converted to /// an unsigned long. pub fn as_u64(&self) -> Result { - let value: i64 = self.as_i64()?; + let value = self.as_i64()?; #[expect(clippy::cast_sign_loss)] Ok(value as u64) } @@ -478,7 +478,7 @@ impl Object { /// if the object is not an instance of `java/lang/Long` or if the value cannot be converted to /// a signed isize. pub fn as_isize(&self) -> Result { - let value: i64 = self.as_i64()?; + let value = self.as_i64()?; #[expect(clippy::cast_possible_truncation)] Ok(value as isize) } @@ -490,7 +490,7 @@ impl Object { /// if the object is not an instance of `java/lang/Long` or if the value cannot be converted to /// an unsigned usize. pub fn as_usize(&self) -> Result { - let value: u64 = self.as_u64()?; + let value = self.as_u64()?; #[expect(clippy::cast_possible_truncation)] Ok(value as usize) } @@ -503,7 +503,7 @@ impl Object { /// a floating-point value. pub fn as_f32(&self) -> Result { let value = self.class_value("java/lang/Float")?; - let value = value.try_into()?; + let value: f32 = value.try_into()?; Ok(value) } @@ -515,7 +515,7 @@ impl Object { /// to a double-precision floating-point value. pub fn as_f64(&self) -> Result { let value = self.class_value("java/lang/Double")?; - let value = value.try_into()?; + let value: f64 = value.try_into()?; Ok(value) } diff --git a/ristretto_classloader/src/reference.rs b/ristretto_classloader/src/reference.rs index 184cf8ac..152308cb 100644 --- a/ristretto_classloader/src/reference.rs +++ b/ristretto_classloader/src/reference.rs @@ -473,6 +473,184 @@ impl Reference { }; Ok(value) } + + /// Convert the object to a boolean value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Boolean`. + /// - if the value cannot be converted to a boolean. + pub fn as_bool(&self) -> Result { + let object = self.as_object_ref()?; + object.as_bool() + } + + /// Convert the object to a character value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Character`. + /// - if the value cannot be converted to a character. + pub fn as_char(&self) -> Result { + let object = self.as_object_ref()?; + object.as_char() + } + + /// Convert the object to a signed byte value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Byte`. + /// - if the value cannot be converted to a signed byte. + pub fn as_i8(&self) -> Result { + let object = self.as_object_ref()?; + object.as_i8() + } + + /// Convert the object to an unsigned byte value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Byte`. + /// - if the value cannot be converted to an unsigned byte. + pub fn as_u8(&self) -> Result { + let object = self.as_object_ref()?; + object.as_u8() + } + + /// Convert the object to a signed short value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Short`. + /// - if the value cannot be converted to a signed short. + pub fn as_i16(&self) -> Result { + let object = self.as_object_ref()?; + object.as_i16() + } + + /// Convert the object to an unsigned short value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Short`. + /// - if the value cannot be converted to an unsigned short. + pub fn as_u16(&self) -> Result { + let object = self.as_object_ref()?; + object.as_u16() + } + + /// Convert the object to a signed integer value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Integer`. + /// - if the value cannot be converted to a signed integer. + pub fn as_i32(&self) -> Result { + let object = self.as_object_ref()?; + object.as_i32() + } + + /// Convert the object to an unsigned integer value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Integer`. + /// - if the value cannot be converted to an unsigned integer. + pub fn as_u32(&self) -> Result { + let object = self.as_object_ref()?; + object.as_u32() + } + + /// Convert the object to a signed long value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Long`. + /// - if the value cannot be converted to a signed long. + pub fn as_i64(&self) -> Result { + let object = self.as_object_ref()?; + object.as_i64() + } + + /// Convert the object to an unsigned long value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Long`. + /// - if the value cannot be converted to an unsigned long. + pub fn as_u64(&self) -> Result { + let object = self.as_object_ref()?; + object.as_u64() + } + + /// Convert the object to a signed isize value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Long`. + /// - if the value cannot be converted to a signed isize. + pub fn as_isize(&self) -> Result { + let object = self.as_object_ref()?; + object.as_isize() + } + + /// Convert the object to an unsigned usize value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Long`. + /// - if the value cannot be converted to an unsigned usize. + pub fn as_usize(&self) -> Result { + let object = self.as_object_ref()?; + object.as_usize() + } + + /// Convert the object to a 32-bit floating point value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Float`. + /// - if the value cannot be converted to a 32-bit floating point value. + pub fn as_f32(&self) -> Result { + let object = self.as_object_ref()?; + object.as_f32() + } + + /// Convert the object to a 64-bit floating point value. + /// + /// # Errors + /// + /// - if the reference is not an `Object`. + /// - if the object is not an instance of `java/lang/Double`. + /// - if the value cannot be converted to a 64-bit floating point value. + pub fn as_f64(&self) -> Result { + let object = self.as_object_ref()?; + object.as_f64() + } + + /// Attempts to convert the reference into a `String`. + /// + /// # Errors + /// + /// if the reference is not an `Object` or if the object cannot be converted to a `String`. + pub fn as_string(&self) -> Result { + let object = self.as_object_ref()?; + object.as_string() + } } impl Display for Reference { @@ -797,317 +975,6 @@ impl From for Reference { } } -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let value = self.as_byte_vec_ref()?.to_vec(); - let value = value.into_iter().map(|v| v != 0).collect(); - Ok(value) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let values = self.as_char_vec_ref()?.to_vec(); - let mut result = Vec::with_capacity(values.len()); - for value in values { - let value = u32::from(value); - let value = char::from_u32(value) - .ok_or(InvalidValueType(format!("Invalid char value {value}")))?; - result.push(value); - } - Ok(result) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - Ok(self.as_byte_vec_ref()?.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let value = self.as_byte_vec_ref()?.to_vec(); - let value: &[u8] = transmute_ref!(value.as_slice()); - Ok(value.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - Ok(self.as_short_vec_ref()?.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let value = self.as_short_vec_ref()?.to_vec(); - let value: &[u16] = transmute_ref!(value.as_slice()); - Ok(value.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - Ok(self.as_int_vec_ref()?.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let value = self.as_int_vec_ref()?.to_vec(); - let value: &[u32] = transmute_ref!(value.as_slice()); - Ok(value.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - Ok(self.as_long_vec_ref()?.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let value = self.as_long_vec_ref()?.to_vec(); - let value: &[u64] = transmute_ref!(value.as_slice()); - Ok(value.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let value: Vec = self.try_into()?; - #[expect(clippy::cast_possible_truncation)] - let value = value.into_iter().map(|v| v as isize).collect(); - Ok(value) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let value: Vec = self.try_into()?; - #[expect(clippy::cast_possible_truncation)] - let value = value.into_iter().map(|v| v as usize).collect(); - Ok(value) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - Ok(self.as_float_vec_ref()?.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - Ok(self.as_double_vec_ref()?.to_vec()) - } -} - -impl TryInto> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result> { - let (_class, values) = self.as_class_vec_ref()?; - let values = values - .iter() - .cloned() - .map(|value| { - if let Some(value) = value { - Value::Object(Some(value)) - } else { - Value::Object(None) - } - }) - .collect(); - Ok(values) - } -} - -impl TryInto<(Arc, Vec>)> for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result<(Arc, Vec>)> { - let (class, references) = self.as_class_vec_ref()?; - Ok((class.clone(), references.to_vec())) - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_bool() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_char() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_i8() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_u8() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_i16() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_u16() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_i32() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_u32() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_i64() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_u64() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_isize() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_usize() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_f32() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_f64() - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - match self { - Reference::Object(object) => Ok(object), - _ => Err(InvalidValueType("Expected object".to_string())), - } - } -} - -impl TryInto for Reference { - type Error = crate::Error; - - fn try_into(self) -> Result { - let object: Object = self.try_into()?; - object.as_string() - } -} - #[cfg(test)] mod tests { use super::*; @@ -2358,346 +2225,171 @@ mod tests { } #[tokio::test] - async fn test_try_into_vec_bool() -> Result<()> { - let original_value = vec![true]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_char() -> Result<()> { - let original_value = vec!['*']; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_i8() -> Result<()> { - let original_value = vec![42i8]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_u8() -> Result<()> { - let original_value = vec![42u8]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_i16() -> Result<()> { - let original_value = vec![42i16]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_u16() -> Result<()> { - let original_value = vec![42u16]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_i32() -> Result<()> { - let original_value = vec![42i32]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_u32() -> Result<()> { - let original_value = vec![42u32]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_i64() -> Result<()> { - let original_value = vec![42i64]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_u64() -> Result<()> { - let original_value = vec![42u64]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_isize() -> Result<()> { - let original_value = vec![42isize]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_usize() -> Result<()> { - let original_value = vec![42usize]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_f32() -> Result<()> { - let original_value = vec![42.1f32]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_f64() -> Result<()> { - let original_value = vec![42.1f64]; - let reference = Reference::from(original_value.clone()); - let value: Vec = reference.try_into()?; - assert_eq!(original_value, value); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_vec_value() -> Result<()> { - let original_class = load_class("[Ljava/lang/Object;").await?; - let class_name = "java.lang.Integer"; - let class = load_class(class_name).await?; - let object = Object::new(class.clone())?; - object.set_value("value", Value::Int(42))?; - let value = Value::from(object); - let original_values = vec![value]; - let reference = Reference::try_from((original_class.clone(), original_values.clone()))?; - let values: Vec = reference.try_into()?; - assert_eq!(original_values, values); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_class_vec() -> Result<()> { - let original_class = load_class("[Ljava/lang/Object;").await?; - let class_name = "java.lang.Integer"; - let class = load_class(class_name).await?; - let object = Object::new(class.clone())?; - object.set_value("value", Value::Int(42))?; - let value = Value::from(object); - let original_values = vec![value]; - let reference = Reference::try_from((original_class.clone(), original_values.clone()))?; - let (reference_class, reference_values) = reference.try_into()?; - assert_eq!(original_class.name(), reference_class.name()); - assert_eq!(original_values.len(), reference_values.len()); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_bool() -> Result<()> { + async fn test_as_bool() -> Result<()> { let class = load_class("java/lang/Boolean").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(1))?; let reference = Reference::from(object); - let value: bool = reference.try_into()?; + let value = reference.as_bool()?; assert!(value); Ok(()) } #[tokio::test] - async fn test_try_into_char() -> Result<()> { + async fn test_as_char() -> Result<()> { let class = load_class("java/lang/Character").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(42))?; let reference = Reference::from(object); - let value: char = reference.try_into()?; + let value = reference.as_char()?; assert_eq!('*', value); Ok(()) } #[tokio::test] - async fn test_try_into_i8() -> Result<()> { + async fn test_as_i8() -> Result<()> { let class = load_class("java/lang/Byte").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(42))?; let reference = Reference::from(object); - let value: i8 = reference.try_into()?; + let value = reference.as_i8()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_u8() -> Result<()> { + async fn test_as_u8() -> Result<()> { let class = load_class("java/lang/Byte").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(42))?; let reference = Reference::from(object); - let value: u8 = reference.try_into()?; + let value = reference.as_u8()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_i16() -> Result<()> { + async fn test_as_i16() -> Result<()> { let class = load_class("java/lang/Short").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(42))?; let reference = Reference::from(object); - let value: i16 = reference.try_into()?; + let value = reference.as_i16()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_u16() -> Result<()> { + async fn test_as_u16() -> Result<()> { let class = load_class("java/lang/Short").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(42))?; let reference = Reference::from(object); - let value: u16 = reference.try_into()?; + let value = reference.as_u16()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_i32() -> Result<()> { + async fn test_as_i32() -> Result<()> { let class = load_class("java/lang/Integer").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(42))?; let reference = Reference::from(object); - let value: i32 = reference.try_into()?; + let value = reference.as_i32()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_u32() -> Result<()> { + async fn test_as_u32() -> Result<()> { let class = load_class("java/lang/Integer").await?; let object = Object::new(class)?; object.set_value("value", Value::Int(42))?; let reference = Reference::from(object); - let value: u32 = reference.try_into()?; + let value = reference.as_u32()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_i64() -> Result<()> { + async fn test_as_i64() -> Result<()> { let class = load_class("java/lang/Long").await?; let object = Object::new(class)?; object.set_value("value", Value::Long(42))?; let reference = Reference::from(object); - let value: i64 = reference.try_into()?; + let value = reference.as_i64()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_u64() -> Result<()> { + async fn test_as_u64() -> Result<()> { let class = load_class("java/lang/Long").await?; let object = Object::new(class)?; object.set_value("value", Value::Long(42))?; let reference = Reference::from(object); - let value: u64 = reference.try_into()?; + let value = reference.as_u64()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_isize() -> Result<()> { + async fn test_as_isize() -> Result<()> { let class = load_class("java/lang/Long").await?; let object = Object::new(class)?; object.set_value("value", Value::Long(42))?; let reference = Reference::from(object); - let value: isize = reference.try_into()?; + let value = reference.as_isize()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_usize() -> Result<()> { + async fn test_as_usize() -> Result<()> { let class = load_class("java/lang/Long").await?; let object = Object::new(class)?; object.set_value("value", Value::Long(42))?; let reference = Reference::from(object); - let value: usize = reference.try_into()?; + let value = reference.as_usize()?; assert_eq!(42, value); Ok(()) } #[tokio::test] - async fn test_try_into_f32() -> Result<()> { + async fn test_as_f32() -> Result<()> { let class = load_class("java/lang/Float").await?; let object = Object::new(class)?; object.set_value("value", Value::Float(42.1))?; let reference = Reference::from(object); - let value: f32 = reference.try_into()?; + let value = reference.as_f32()?; let value = value - 42.1f32; assert!(value.abs() < 0.1f32); Ok(()) } #[tokio::test] - async fn test_try_into_f64() -> Result<()> { + async fn test_as_f64() -> Result<()> { let class = load_class("java/lang/Double").await?; let object = Object::new(class)?; object.set_value("value", Value::Double(42.1))?; let reference = Reference::from(object); - let value: f64 = reference.try_into()?; + let value = reference.as_f64()?; let value = value - 42.1f64; assert!(value.abs() < 0.1f64); Ok(()) } - #[tokio::test] - async fn test_try_into_object() -> Result<()> { - let class_name = "java.lang.Object"; - let class = load_class(class_name).await?; - let reference = Reference::from(Object::new(class)?); - let object: Object = reference.try_into()?; - assert_eq!("java/lang/Object", object.class().name()); - Ok(()) - } - - #[tokio::test] - async fn test_try_into_object_error() -> Result<()> { - let array = vec![42]; - let reference = Reference::from(array); - let result: Result = reference.try_into(); - assert!(matches!(result, Err(InvalidValueType(_)))); - Ok(()) - } - #[expect(clippy::cast_possible_wrap)] #[tokio::test] - async fn test_try_into_string() -> Result<()> { + async fn test_as_string() -> Result<()> { let class = load_class("java/lang/String").await?; let object = Object::new(class)?; let string_bytes: Vec = "foo".as_bytes().to_vec().iter().map(|&b| b as i8).collect(); let string_value = Value::from(string_bytes); object.set_value("value", string_value)?; - let result = object.as_string()?; + let reference = Reference::from(object); + let result = reference.as_string()?; assert_eq!("foo".to_string(), result); Ok(()) } diff --git a/ristretto_classloader/src/value.rs b/ristretto_classloader/src/value.rs index d5325bf1..451f85cd 100644 --- a/ristretto_classloader/src/value.rs +++ b/ristretto_classloader/src/value.rs @@ -4,7 +4,8 @@ use crate::{Class, Object, Result}; use std::fmt; use std::fmt::Display; use std::hash::{Hash, Hasher}; -use std::sync::Arc; +use std::sync::{Arc, RwLockReadGuard, RwLockWriteGuard}; +use zerocopy::transmute_ref; /// Represents a value in the Ristretto VM. #[derive(Clone, Debug)] @@ -61,6 +62,42 @@ impl Value { Ok(value) } + + /// Returns a reference to `Vec>`. + /// + /// # Errors + /// + /// if the value is not a `Reference::Array` + #[expect(clippy::type_complexity)] + pub fn as_class_vec_ref( + &self, + ) -> Result<(&Arc, RwLockReadGuard<'_, Vec>>)> { + let reference = self.as_reference()?; + reference.as_class_vec_ref() + } + + /// Returns a mutable reference to `Vec>`. + /// + /// # Errors + /// + /// if the value is not a `Reference::Array` + #[expect(clippy::type_complexity)] + pub fn as_class_vec_mut( + &self, + ) -> Result<(&Arc, RwLockWriteGuard<'_, Vec>>)> { + let reference = self.as_reference()?; + reference.as_class_vec_mut() + } + + /// Returns a reference to an `Object`. + /// + /// # Errors + /// + /// if the value is not an Object. + pub fn as_object_ref(&self) -> Result<&Object> { + let reference = self.as_reference()?; + reference.as_object_ref() + } } impl Display for Value { @@ -336,7 +373,9 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + let value = reference.as_byte_vec_ref()?.to_vec(); + let value = value.into_iter().map(|v| v != 0).collect(); + Ok(value) } } @@ -345,7 +384,15 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + let values = reference.as_char_vec_ref()?.to_vec(); + let mut result = Vec::with_capacity(values.len()); + for value in values { + let value = u32::from(value); + let value = char::from_u32(value) + .ok_or(InvalidValueType(format!("Invalid char value {value}")))?; + result.push(value); + } + Ok(result) } } @@ -354,7 +401,7 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + Ok(reference.as_byte_vec_ref()?.to_vec()) } } @@ -363,7 +410,9 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + let value = reference.as_byte_vec_ref()?.to_vec(); + let value: &[u8] = transmute_ref!(value.as_slice()); + Ok(value.to_vec()) } } @@ -372,7 +421,7 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + Ok(reference.as_short_vec_ref()?.to_vec()) } } @@ -381,7 +430,9 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + let value = reference.as_short_vec_ref()?.to_vec(); + let value: &[u16] = transmute_ref!(value.as_slice()); + Ok(value.to_vec()) } } @@ -390,7 +441,7 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + Ok(reference.as_int_vec_ref()?.to_vec()) } } @@ -399,7 +450,9 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + let value = reference.as_int_vec_ref()?.to_vec(); + let value: &[u32] = transmute_ref!(value.as_slice()); + Ok(value.to_vec()) } } @@ -408,7 +461,7 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + Ok(reference.as_long_vec_ref()?.to_vec()) } } @@ -417,7 +470,9 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + let value = reference.as_long_vec_ref()?.to_vec(); + let value: &[u64] = transmute_ref!(value.as_slice()); + Ok(value.to_vec()) } } @@ -425,8 +480,10 @@ impl TryInto> for Value { type Error = crate::Error; fn try_into(self) -> Result> { - let reference: Reference = self.try_into()?; - reference.try_into() + let value: Vec = self.try_into()?; + #[expect(clippy::cast_possible_truncation)] + let value = value.into_iter().map(|v| v as isize).collect(); + Ok(value) } } @@ -434,8 +491,10 @@ impl TryInto> for Value { type Error = crate::Error; fn try_into(self) -> Result> { - let reference: Reference = self.try_into()?; - reference.try_into() + let value: Vec = self.try_into()?; + #[expect(clippy::cast_possible_truncation)] + let value = value.into_iter().map(|v| v as usize).collect(); + Ok(value) } } @@ -444,7 +503,7 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + Ok(reference.as_float_vec_ref()?.to_vec()) } } @@ -453,7 +512,7 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + Ok(reference.as_double_vec_ref()?.to_vec()) } } @@ -462,7 +521,19 @@ impl TryInto> for Value { fn try_into(self) -> Result> { let reference: Reference = self.try_into()?; - reference.try_into() + let (_class, values) = reference.as_class_vec_ref()?; + let values = values + .iter() + .cloned() + .map(|value| { + if let Some(value) = value { + Value::Object(Some(value)) + } else { + Value::Object(None) + } + }) + .collect(); + Ok(values) } } @@ -474,7 +545,7 @@ impl TryInto for Value { Ok(value != 0) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_bool() } } } @@ -491,7 +562,7 @@ impl TryInto for Value { Ok(value) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_char() } } } @@ -504,7 +575,7 @@ impl TryInto for Value { Ok(i8::try_from(value)?) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_i8() } } } @@ -526,7 +597,7 @@ impl TryInto for Value { Ok(i16::try_from(value)?) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_i16() } } } @@ -548,7 +619,7 @@ impl TryInto for Value { Ok(value) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_i32() } } } @@ -570,7 +641,7 @@ impl TryInto for Value { Ok(value) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_i64() } } } @@ -610,7 +681,7 @@ impl TryInto for Value { Ok(value) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_f32() } } } @@ -623,7 +694,7 @@ impl TryInto for Value { Ok(value) } else { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_f64() } } } @@ -633,7 +704,8 @@ impl TryInto for Value { fn try_into(self) -> Result { let reference: Reference = self.try_into()?; - reference.try_into() + let object = reference.as_object_ref()?.clone(); + Ok(object) } } @@ -653,7 +725,7 @@ impl TryInto for Value { fn try_into(self) -> Result { let reference: Reference = self.try_into()?; - reference.try_into() + reference.as_string() } } @@ -1353,20 +1425,36 @@ mod tests { } #[tokio::test] - async fn test_try_into_class_vec() -> Result<()> { + async fn test_as_class_vec_ref() -> Result<()> { let original_class = load_class("[Ljava/lang/Object;").await?; - let class_name = "java/lang/Integer"; - let class = load_class(class_name).await?; - let object = Object::new(class.clone())?; - object.set_value("value", Value::Int(42))?; - let value = Value::from(object); - let original_values = vec![value]; - let value = Value::try_from((original_class.clone(), original_values.clone()))?; - let reference: Reference = value.try_into()?; - let reference_class_name = reference.class_name().to_string(); - let reference_values: Vec = reference.try_into()?; - assert_eq!(original_class.name(), reference_class_name); - assert_eq!(original_values.len(), reference_values.len()); + let original_value = vec![None]; + let value = Value::from((original_class.clone(), original_value.clone())); + let (class, value) = value.as_class_vec_ref()?; + assert_eq!(&original_class, class); + assert_eq!(original_value, value.to_vec()); + Ok(()) + } + + #[tokio::test] + async fn test_as_class_vec_mut() -> Result<()> { + let object_class = load_class("[Ljava/lang/Object;").await?; + let value = Value::from((object_class.clone(), vec![])); + { + let (_class, mut mutable_reference) = value.as_class_vec_mut()?; + mutable_reference.push(None); + } + let (_class, array) = value.as_class_vec_ref()?; + assert_eq!(array.to_vec(), vec![None]); + Ok(()) + } + + #[tokio::test] + async fn test_as_object_ref() -> Result<()> { + let class = load_class("java.lang.Object").await?; + let object = Object::new(class)?; + let reference = Reference::from(object.clone()); + let result = reference.as_object_ref()?; + assert_eq!(&object, result); Ok(()) } diff --git a/ristretto_vm/src/intrinsic_methods/java/io/unixfilesystem.rs b/ristretto_vm/src/intrinsic_methods/java/io/unixfilesystem.rs index 026c56c6..e08a5b9e 100644 --- a/ristretto_vm/src/intrinsic_methods/java/io/unixfilesystem.rs +++ b/ristretto_vm/src/intrinsic_methods/java/io/unixfilesystem.rs @@ -1049,11 +1049,9 @@ mod tests { let mut parameters = Parameters::default(); parameters.push(file_object); let value = list(thread, parameters).await?.expect("paths"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let elements: Vec = reference.try_into()?; - assert_eq!(class_name, "java/lang/String"); - assert!(!elements.is_empty()); + let (class, values) = value.as_class_vec_ref()?; + assert_eq!(class.name(), "java/lang/String"); + assert!(!values.is_empty()); Ok(()) } diff --git a/ristretto_vm/src/intrinsic_methods/java/lang/class.rs b/ristretto_vm/src/intrinsic_methods/java/lang/class.rs index 0a2f3383..6e347bd7 100644 --- a/ristretto_vm/src/intrinsic_methods/java/lang/class.rs +++ b/ristretto_vm/src/intrinsic_methods/java/lang/class.rs @@ -1186,13 +1186,12 @@ mod tests { let value = get_declared_classes_0(thread, parameters) .await? .expect("interfaces"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!(class_name, "[Ljava/lang/Class;"); + let (class, values) = value.as_class_vec_ref()?; + assert_eq!(class.name(), "[Ljava/lang/Class;"); let mut class_names = Vec::new(); - for reference in values { - let object: Object = reference.try_into()?; + for reference in values.iter().cloned() { + let reference = reference.expect("interfaces"); + let object = reference.as_object_ref()?; let class_name = object.value("name")?; let class_name: String = class_name.try_into()?; class_names.push(class_name); @@ -1213,10 +1212,8 @@ mod tests { let value = get_declared_constructors_0(thread, parameters) .await? .expect("constructors"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!(class_name, "[Ljava/lang/reflect/Constructor;"); + let (class, values) = value.as_class_vec_ref()?; + assert_eq!(class.name(), "[Ljava/lang/reflect/Constructor;"); assert_eq!(2, values.len()); // TODO: Enable test assertions when invokedynamic is implemented // let mut signatures = Vec::new(); @@ -1253,12 +1250,19 @@ mod tests { let value = get_declared_fields_0(thread, parameters) .await? .expect("fields"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!(class_name, "[Ljava/lang/reflect/Field;"); + let (class, references) = { + let (class, values) = value.as_class_vec_ref()?; + let references = values + .iter() + .cloned() + .map(|reference| reference.expect("reference")) + .collect::>(); + (class, references) + }; + assert_eq!(class.name(), "[Ljava/lang/reflect/Field;"); let mut signatures = Vec::new(); - for value in values { + for reference in references.into_iter() { + let value = Value::from(reference); let result = vm .invoke( "java.lang.reflect.Field", @@ -1297,12 +1301,19 @@ mod tests { let value = get_declared_methods_0(thread, parameters) .await? .expect("methods"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!(class_name, "[Ljava/lang/reflect/Method;"); + let (class, references) = { + let (class, values) = value.as_class_vec_ref()?; + let references = values + .iter() + .cloned() + .map(|reference| reference.expect("reference")) + .collect::>(); + (class, references) + }; + assert_eq!(class.name(), "[Ljava/lang/reflect/Method;"); let mut method_names = Vec::new(); - for value in values { + for reference in references.into_iter() { + let value = Value::from(reference); let result = vm .invoke( "java.lang.reflect.Method", @@ -1438,13 +1449,12 @@ mod tests { let value = get_interfaces_0(thread, parameters) .await? .expect("interfaces"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!(class_name, "[Ljava/lang/Class;"); + let (class, values) = value.as_class_vec_ref()?; + assert_eq!(class.name(), "[Ljava/lang/Class;"); let mut class_names = Vec::new(); - for reference in values { - let object: Object = reference.try_into()?; + for reference in values.iter().cloned() { + let reference = reference.expect("reference"); + let object = reference.as_object_ref()?; let class_name = object.value("name")?; let class_name: String = class_name.try_into()?; class_names.push(class_name); diff --git a/ristretto_vm/src/intrinsic_methods/java/lang/classloader.rs b/ristretto_vm/src/intrinsic_methods/java/lang/classloader.rs index cbd4ee66..cfa6460e 100644 --- a/ristretto_vm/src/intrinsic_methods/java/lang/classloader.rs +++ b/ristretto_vm/src/intrinsic_methods/java/lang/classloader.rs @@ -45,7 +45,7 @@ async fn class_object_from_bytes( } if let Some(source_file) = source_file { - let _source_file: String = source_file.try_into()?; + let _source_file = source_file.as_string()?; // TODO: implement setting the source file } @@ -70,7 +70,7 @@ pub(crate) async fn define_class_0_0( let bytes: Vec = parameters.pop()?.try_into()?; let class = class_object_from_bytes(&thread, None, &bytes, offset, length).await?; if let Some(expected_class_name) = parameters.pop_reference()? { - let expected_class_name: String = expected_class_name.try_into()?; + let expected_class_name = expected_class_name.as_string()?; let class_name = class.class().name(); if class_name != expected_class_name { return Err(NoClassDefFoundError(class_name.to_string()).into()); @@ -95,7 +95,7 @@ pub(crate) async fn define_class_1_0( let bytes: Vec = parameters.pop()?.try_into()?; let class = class_object_from_bytes(&thread, source_file, &bytes, offset, length).await?; if let Some(expected_class_name) = parameters.pop_reference()? { - let expected_class_name: String = expected_class_name.try_into()?; + let expected_class_name = expected_class_name.as_string()?; let class_name = class.class().name(); if class_name != expected_class_name { return Err(NoClassDefFoundError(class_name.to_string()).into()); @@ -123,7 +123,7 @@ pub(crate) async fn define_class_2_0( let bytes: Vec = buffer.into_iter().skip(buffer_offset).collect(); let class = class_object_from_bytes(&thread, source_file, &bytes, offset, length).await?; if let Some(expected_class_name) = parameters.pop_reference()? { - let expected_class_name: String = expected_class_name.try_into()?; + let expected_class_name = expected_class_name.as_string()?; let class_name = class.class().name(); if class_name != expected_class_name { return Err(NoClassDefFoundError(class_name.to_string()).into()); diff --git a/ristretto_vm/src/intrinsic_methods/jdk/internal/reflect/constantpool.rs b/ristretto_vm/src/intrinsic_methods/jdk/internal/reflect/constantpool.rs index 1d2a0653..f3af91b5 100644 --- a/ristretto_vm/src/intrinsic_methods/jdk/internal/reflect/constantpool.rs +++ b/ristretto_vm/src/intrinsic_methods/jdk/internal/reflect/constantpool.rs @@ -732,14 +732,17 @@ pub(crate) mod tests { let value = get_member_ref_info_at(thread, parameters) .await? .expect("value"); - let result: Reference = value.try_into()?; - let class_name = result.class_name().to_string(); - let values: Vec = result.try_into()?; - assert_eq!("java/lang/String", class_name); + let (class, values) = value.as_class_vec_ref()?; + let references = values + .iter() + .cloned() + .map(|reference| reference.expect("reference")) + .collect::>(); + assert_eq!("java/lang/String", class.name()); assert_eq!(3, values.len()); - let class_name: String = values.first().expect("value").clone().try_into()?; - let name: String = values.get(1).expect("value").clone().try_into()?; - let descriptor: String = values.get(2).expect("value").clone().try_into()?; + let class_name = references.first().expect("reference").as_string()?; + let name = references.get(1).expect("reference").as_string()?; + let descriptor = references.get(2).expect("reference").as_string()?; assert_eq!("TestClass", class_name); assert_eq!("x", name); assert_eq!("I", descriptor); @@ -759,14 +762,17 @@ pub(crate) mod tests { let value = get_member_ref_info_at(thread, parameters) .await? .expect("value"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!("java/lang/String", class_name); + let (class, values) = value.as_class_vec_ref()?; + let references = values + .iter() + .cloned() + .map(|reference| reference.expect("reference")) + .collect::>(); + assert_eq!("java/lang/String", class.name()); assert_eq!(3, values.len()); - let class_name: String = values.first().expect("value").clone().try_into()?; - let name: String = values.get(1).expect("value").clone().try_into()?; - let descriptor: String = values.get(2).expect("value").clone().try_into()?; + let class_name = references.first().expect("value").as_string()?; + let name = references.get(1).expect("value").as_string()?; + let descriptor = references.get(2).expect("value").as_string()?; assert_eq!("java/lang/Object", class_name); assert_eq!("", name); assert_eq!("()V", descriptor); @@ -883,13 +889,16 @@ pub(crate) mod tests { let value = get_name_and_type_ref_info_at_0(thread, parameters) .await? .expect("value"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!("java/lang/String", class_name); + let (class, values) = value.as_class_vec_ref()?; + let references = values + .iter() + .cloned() + .map(|reference| reference.expect("reference")) + .collect::>(); + assert_eq!("java/lang/String", class.name()); assert_eq!(2, values.len()); - let name: String = values.first().expect("value").clone().try_into()?; - let descriptor: String = values.get(1).expect("value").clone().try_into()?; + let name = references.first().expect("value").as_string()?; + let descriptor = references.get(1).expect("value").as_string()?; assert_eq!("x", name); assert_eq!("I", descriptor); Ok(()) @@ -902,13 +911,16 @@ pub(crate) mod tests { let value = get_name_and_type_ref_info_at_0(thread, parameters) .await? .expect("value"); - let reference: Reference = value.try_into()?; - let class_name = reference.class_name().to_string(); - let values: Vec = reference.try_into()?; - assert_eq!("java/lang/String", class_name); + let (class, values) = value.as_class_vec_ref()?; + let references = values + .iter() + .cloned() + .map(|reference| reference.expect("reference")) + .collect::>(); + assert_eq!("java/lang/String", class.name()); assert_eq!(2, values.len()); - let name: String = values.first().expect("value").clone().try_into()?; - let descriptor: String = values.get(1).expect("value").clone().try_into()?; + let name = references.first().expect("value").as_string()?; + let descriptor = references.get(1).expect("value").as_string()?; assert_eq!("", name); assert_eq!("()V", descriptor); Ok(())