ruffle/core/src/avm2/parameters.rs

185 lines
5.8 KiB
Rust

use crate::avm2::error::type_error;
use crate::avm2::object::PrimitiveObject;
use crate::avm2::Object;
use crate::avm2::{Activation, Error, Value};
use crate::string::AvmString;
/// Extensions over parameters that are passed into AS-defined, Rust-implemented methods.
///
/// It is expected that the AS signature is correct and you only operate on values defined from it.
/// These values will be `expect()`ed to exist, and any method here will panic if they're missing.
pub trait ParametersExt<'gc> {
/// Gets the value at the given index.
fn get_value(&self, index: usize) -> Value<'gc>;
/// Gets the value at the given index and coerces it to an Object.
///
/// If the value is null or is undefined, a TypeError 2007 is raised.
fn get_object(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
name: &'static str,
) -> Result<Object<'gc>, Error<'gc>>;
/// Tries to get the value at the given index and coerce it to an Object.
///
/// If the value is null or is undefined, None is returned.
fn try_get_object(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Option<Object<'gc>>;
/// Gets the value at the given index and coerces it to an f64.
///
/// If the value is null or is undefined, 0.0 is returned.
/// If the object cannot be coerced to an f64, a TypeError 1050 is raised.
fn get_f64(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<f64, Error<'gc>>;
/// Gets the value at the given index and coerces it to a u32.
///
/// If the value is null or is undefined, 0 is returned.
/// If the object cannot be coerced to a u32, a TypeError 1050 is raised.
fn get_u32(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<u32, Error<'gc>>;
/// Gets the value at the given index and coerces it to a i32.
///
/// If the value is null or is undefined, 0 is returned.
/// If the object cannot be coerced to an i32, a TypeError 1050 is raised.
fn get_i32(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<i32, Error<'gc>>;
/// Gets the value at the given index and coerces it to a bool.
///
/// If the value is null or is undefined, false is returned.
fn get_bool(&self, index: usize) -> bool;
/// Gets the value at the given index and coerces it to an AvmString.
///
/// If the value is undefined, "undefined" is returned.
/// If the value is null, "null" is returned.
/// If the object cannot be coerced to a string, a TypeError 1050 is raised.
fn get_string(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<AvmString<'gc>, Error<'gc>>;
/// Gets the value at the given index and coerces it to an AvmString.
///
/// If the value is null or is undefined, Ok(None) is returned.
/// If the object cannot be coerced to a string, a TypeError 1050 is raised.
fn try_get_string(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<Option<AvmString<'gc>>, Error<'gc>>;
}
impl<'gc> ParametersExt<'gc> for &[Value<'gc>] {
#[inline]
fn get_value(&self, index: usize) -> Value<'gc> {
self[index]
}
fn get_object(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
name: &'static str,
) -> Result<Object<'gc>, Error<'gc>> {
match self[index] {
Value::Null | Value::Undefined => Err(null_parameter_error(activation, name)),
Value::Object(o) => Ok(o),
primitive => Ok(PrimitiveObject::from_primitive(primitive, activation)
.expect("Primitive object is infallible at this point")),
}
}
fn try_get_object(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Option<Object<'gc>> {
match self[index] {
Value::Null | Value::Undefined => None,
Value::Object(o) => Some(o),
primitive => Some(
PrimitiveObject::from_primitive(primitive, activation)
.expect("Primitive object is infallible at this point"),
),
}
}
fn get_f64(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<f64, Error<'gc>> {
self[index].coerce_to_number(activation)
}
fn get_u32(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<u32, Error<'gc>> {
self[index].coerce_to_u32(activation)
}
fn get_i32(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<i32, Error<'gc>> {
self[index].coerce_to_i32(activation)
}
fn get_bool(&self, index: usize) -> bool {
self[index].coerce_to_boolean()
}
fn get_string(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<AvmString<'gc>, Error<'gc>> {
self[index].coerce_to_string(activation)
}
fn try_get_string(
&self,
activation: &mut Activation<'_, 'gc>,
index: usize,
) -> Result<Option<AvmString<'gc>>, Error<'gc>> {
match self[index] {
Value::Null | Value::Undefined => Ok(None),
other => Ok(Some(other.coerce_to_string(activation)?)),
}
}
}
pub fn null_parameter_error<'gc>(activation: &mut Activation<'_, 'gc>, name: &str) -> Error<'gc> {
let error = type_error(
activation,
&format!("Error #2007: Parameter {name} must be non-null."),
2007,
);
match error {
Err(e) => e,
Ok(e) => Error::AvmError(e),
}
}