avm1: don't use &str methods when parsing enum parameters in MovieClip
This commit is contained in:
parent
d850085d2b
commit
1d9d7e6942
|
@ -5,7 +5,7 @@ use crate::avm1::error::Error;
|
||||||
use crate::avm1::object::bevel_filter::{BevelFilterObject, BevelFilterType};
|
use crate::avm1::object::bevel_filter::{BevelFilterObject, BevelFilterType};
|
||||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||||
use crate::avm1::{Object, TObject, Value};
|
use crate::avm1::{Object, TObject, Value};
|
||||||
use crate::string::AvmString;
|
use crate::string::{AvmString, BorrowWStr, WStr};
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
||||||
|
@ -378,8 +378,8 @@ pub fn get_type<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(filter) = this.as_bevel_filter_object() {
|
if let Some(filter) = this.as_bevel_filter_object() {
|
||||||
let type_: &str = filter.get_type().into();
|
let type_: WStr<'_> = filter.get_type().into();
|
||||||
return Ok(AvmString::new(activation.context.gc_context, type_.to_string()).into());
|
return Ok(AvmString::new_ucs2(activation.context.gc_context, type_.into()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -394,7 +394,7 @@ pub fn set_type<'gc>(
|
||||||
.get(0)
|
.get(0)
|
||||||
.unwrap_or(&"inner".into())
|
.unwrap_or(&"inner".into())
|
||||||
.coerce_to_string(activation)
|
.coerce_to_string(activation)
|
||||||
.map(|s| s.as_str().into())?;
|
.map(|s| s.borrow().into())?;
|
||||||
|
|
||||||
if let Some(filter) = this.as_bevel_filter_object() {
|
if let Some(filter) = this.as_bevel_filter_object() {
|
||||||
filter.set_type(activation.context.gc_context, type_);
|
filter.set_type(activation.context.gc_context, type_);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::avm1::error::Error;
|
||||||
use crate::avm1::object::displacement_map_filter::DisplacementMapFilterObject;
|
use crate::avm1::object::displacement_map_filter::DisplacementMapFilterObject;
|
||||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||||
use crate::avm1::{Object, TObject, Value};
|
use crate::avm1::{Object, TObject, Value};
|
||||||
use crate::string::AvmString;
|
use crate::string::{AvmString, BorrowWStr, WStr};
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
||||||
|
@ -224,9 +224,8 @@ pub fn mode<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(object) = this.as_displacement_map_filter_object() {
|
if let Some(object) = this.as_displacement_map_filter_object() {
|
||||||
return Ok(
|
let mode: WStr<'_> = object.mode().into();
|
||||||
AvmString::new(activation.context.gc_context, String::from(object.mode())).into(),
|
return Ok(AvmString::new_ucs2(activation.context.gc_context, mode.into()).into());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -243,7 +242,7 @@ pub fn set_mode<'gc>(
|
||||||
.coerce_to_string(activation)?;
|
.coerce_to_string(activation)?;
|
||||||
|
|
||||||
if let Some(object) = this.as_displacement_map_filter_object() {
|
if let Some(object) = this.as_displacement_map_filter_object() {
|
||||||
object.set_mode(activation.context.gc_context, mode.as_str().into());
|
object.set_mode(activation.context.gc_context, mode.borrow().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::avm1::object::bevel_filter::BevelFilterType;
|
||||||
use crate::avm1::object::gradient_bevel_filter::GradientBevelFilterObject;
|
use crate::avm1::object::gradient_bevel_filter::GradientBevelFilterObject;
|
||||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||||
use crate::avm1::{ArrayObject, Object, TObject, Value};
|
use crate::avm1::{ArrayObject, Object, TObject, Value};
|
||||||
use crate::string::AvmString;
|
use crate::string::{AvmString, BorrowWStr, WStr};
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
||||||
|
@ -392,8 +392,8 @@ pub fn get_type<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(filter) = this.as_gradient_bevel_filter_object() {
|
if let Some(filter) = this.as_gradient_bevel_filter_object() {
|
||||||
let type_: &str = filter.get_type().into();
|
let type_: WStr<'_> = filter.get_type().into();
|
||||||
return Ok(AvmString::new(activation.context.gc_context, type_.to_string()).into());
|
return Ok(AvmString::new_ucs2(activation.context.gc_context, type_.into()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -408,7 +408,7 @@ pub fn set_type<'gc>(
|
||||||
.get(0)
|
.get(0)
|
||||||
.unwrap_or(&"inner".into())
|
.unwrap_or(&"inner".into())
|
||||||
.coerce_to_string(activation)
|
.coerce_to_string(activation)
|
||||||
.map(|s| s.as_str().into())?;
|
.map(|s| s.borrow().into())?;
|
||||||
|
|
||||||
if let Some(filter) = this.as_gradient_bevel_filter_object() {
|
if let Some(filter) = this.as_gradient_bevel_filter_object() {
|
||||||
filter.set_type(activation.context.gc_context, type_);
|
filter.set_type(activation.context.gc_context, type_);
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::avm1::object::bevel_filter::BevelFilterType;
|
||||||
use crate::avm1::object::gradient_glow_filter::GradientGlowFilterObject;
|
use crate::avm1::object::gradient_glow_filter::GradientGlowFilterObject;
|
||||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||||
use crate::avm1::{ArrayObject, Object, TObject, Value};
|
use crate::avm1::{ArrayObject, Object, TObject, Value};
|
||||||
use crate::string::AvmString;
|
use crate::string::{AvmString, BorrowWStr, WStr};
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
const PROTO_DECLS: &[Declaration] = declare_properties! {
|
||||||
|
@ -392,8 +392,8 @@ pub fn get_type<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(filter) = this.as_gradient_glow_filter_object() {
|
if let Some(filter) = this.as_gradient_glow_filter_object() {
|
||||||
let type_: &str = filter.get_type().into();
|
let type_: WStr<'_> = filter.get_type().into();
|
||||||
return Ok(AvmString::new(activation.context.gc_context, type_.to_string()).into());
|
return Ok(AvmString::new_ucs2(activation.context.gc_context, type_.into()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -408,7 +408,7 @@ pub fn set_type<'gc>(
|
||||||
.get(0)
|
.get(0)
|
||||||
.unwrap_or(&"inner".into())
|
.unwrap_or(&"inner".into())
|
||||||
.coerce_to_string(activation)
|
.coerce_to_string(activation)
|
||||||
.map(|s| s.as_str().into())?;
|
.map(|s| s.borrow().into())?;
|
||||||
|
|
||||||
if let Some(filter) = this.as_gradient_glow_filter_object() {
|
if let Some(filter) = this.as_gradient_glow_filter_object() {
|
||||||
filter.set_type(activation.context.gc_context, type_);
|
filter.set_type(activation.context.gc_context, type_);
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::display_object::{
|
||||||
use crate::ecma_conversions::f64_to_wrapping_i32;
|
use crate::ecma_conversions::f64_to_wrapping_i32;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::shape_utils::DrawCommand;
|
use crate::shape_utils::DrawCommand;
|
||||||
use crate::string::AvmString;
|
use crate::string::{AvmString, BorrowWStr};
|
||||||
use crate::vminterface::Instantiator;
|
use crate::vminterface::Instantiator;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -262,28 +262,31 @@ fn line_style<'gc>(
|
||||||
let (allow_scale_x, allow_scale_y) = match args
|
let (allow_scale_x, allow_scale_y) = match args
|
||||||
.get(4)
|
.get(4)
|
||||||
.and_then(|v| v.coerce_to_string(activation).ok())
|
.and_then(|v| v.coerce_to_string(activation).ok())
|
||||||
.as_deref()
|
.as_ref()
|
||||||
|
.map(|v| v.borrow())
|
||||||
{
|
{
|
||||||
Some("normal") => (true, true),
|
Some(v) if v == b"normal" => (true, true),
|
||||||
Some("vertical") => (true, false),
|
Some(v) if v == b"vertical" => (true, false),
|
||||||
Some("horizontal") => (false, true),
|
Some(v) if v == b"horizontal" => (false, true),
|
||||||
_ => (false, false),
|
_ => (false, false),
|
||||||
};
|
};
|
||||||
let cap_style = match args
|
let cap_style = match args
|
||||||
.get(5)
|
.get(5)
|
||||||
.and_then(|v| v.coerce_to_string(activation).ok())
|
.and_then(|v| v.coerce_to_string(activation).ok())
|
||||||
.as_deref()
|
.as_ref()
|
||||||
|
.map(|v| v.borrow())
|
||||||
{
|
{
|
||||||
Some("square") => LineCapStyle::Square,
|
Some(v) if v == b"square" => LineCapStyle::Square,
|
||||||
Some("none") => LineCapStyle::None,
|
Some(v) if v == b"none" => LineCapStyle::None,
|
||||||
_ => LineCapStyle::Round,
|
_ => LineCapStyle::Round,
|
||||||
};
|
};
|
||||||
let join_style = match args
|
let join_style = match args
|
||||||
.get(6)
|
.get(6)
|
||||||
.and_then(|v| v.coerce_to_string(activation).ok())
|
.and_then(|v| v.coerce_to_string(activation).ok())
|
||||||
.as_deref()
|
.as_ref()
|
||||||
|
.map(|v| v.borrow())
|
||||||
{
|
{
|
||||||
Some("miter") => {
|
Some(v) if v == b"miter" => {
|
||||||
if let Some(limit) = args.get(7) {
|
if let Some(limit) = args.get(7) {
|
||||||
let limit = limit.coerce_to_f64(activation)?.clamp(0.0, 255.0);
|
let limit = limit.coerce_to_f64(activation)?.clamp(0.0, 255.0);
|
||||||
LineJoinStyle::Miter(Fixed8::from_f64(limit))
|
LineJoinStyle::Miter(Fixed8::from_f64(limit))
|
||||||
|
@ -291,7 +294,7 @@ fn line_style<'gc>(
|
||||||
LineJoinStyle::Miter(Fixed8::from_f32(3.0))
|
LineJoinStyle::Miter(Fixed8::from_f32(3.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some("bevel") => LineJoinStyle::Bevel,
|
Some(v) if v == b"bevel" => LineJoinStyle::Bevel,
|
||||||
_ => LineJoinStyle::Round,
|
_ => LineJoinStyle::Round,
|
||||||
};
|
};
|
||||||
movie_clip
|
movie_clip
|
||||||
|
@ -468,18 +471,20 @@ fn begin_gradient_fill<'gc>(
|
||||||
let spread = match args
|
let spread = match args
|
||||||
.get(5)
|
.get(5)
|
||||||
.and_then(|v| v.coerce_to_string(activation).ok())
|
.and_then(|v| v.coerce_to_string(activation).ok())
|
||||||
.as_deref()
|
.as_ref()
|
||||||
|
.map(|v| v.borrow())
|
||||||
{
|
{
|
||||||
Some("reflect") => GradientSpread::Reflect,
|
Some(v) if v == b"reflect" => GradientSpread::Reflect,
|
||||||
Some("repeat") => GradientSpread::Repeat,
|
Some(v) if v == b"repeat" => GradientSpread::Repeat,
|
||||||
_ => GradientSpread::Pad,
|
_ => GradientSpread::Pad,
|
||||||
};
|
};
|
||||||
let interpolation = match args
|
let interpolation = match args
|
||||||
.get(6)
|
.get(6)
|
||||||
.and_then(|v| v.coerce_to_string(activation).ok())
|
.and_then(|v| v.coerce_to_string(activation).ok())
|
||||||
.as_deref()
|
.as_ref()
|
||||||
|
.map(|v| v.borrow())
|
||||||
{
|
{
|
||||||
Some("linearRGB") => GradientInterpolation::LinearRgb,
|
Some(v) if v == b"linearRGB" => GradientInterpolation::LinearRgb,
|
||||||
_ => GradientInterpolation::Rgb,
|
_ => GradientInterpolation::Rgb,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -489,9 +494,9 @@ fn begin_gradient_fill<'gc>(
|
||||||
interpolation,
|
interpolation,
|
||||||
records,
|
records,
|
||||||
};
|
};
|
||||||
let style = match method.as_ref() {
|
let style = if method == b"linear" {
|
||||||
"linear" => FillStyle::LinearGradient(gradient),
|
FillStyle::LinearGradient(gradient)
|
||||||
"radial" => {
|
} else if method == b"radial" {
|
||||||
if let Some(focal_point) = args.get(7) {
|
if let Some(focal_point) = args.get(7) {
|
||||||
FillStyle::FocalGradient {
|
FillStyle::FocalGradient {
|
||||||
gradient,
|
gradient,
|
||||||
|
@ -500,15 +505,13 @@ fn begin_gradient_fill<'gc>(
|
||||||
} else {
|
} else {
|
||||||
FillStyle::RadialGradient(gradient)
|
FillStyle::RadialGradient(gradient)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
other => {
|
|
||||||
avm_warn!(
|
avm_warn!(
|
||||||
activation,
|
activation,
|
||||||
"beginGradientFill() received invalid fill type {:?}",
|
"beginGradientFill() received invalid fill type {:?}",
|
||||||
other
|
method
|
||||||
);
|
);
|
||||||
return Ok(Value::Undefined);
|
return Ok(Value::Undefined);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
movie_clip
|
movie_clip
|
||||||
.as_drawing(activation.context.gc_context)
|
.as_drawing(activation.context.gc_context)
|
||||||
|
@ -1004,7 +1007,7 @@ pub fn goto_frame<'gc>(
|
||||||
activation.resolve_variable_path(movie_clip.into(), &frame_path)?
|
activation.resolve_variable_path(movie_clip.into(), &frame_path)?
|
||||||
{
|
{
|
||||||
if let Some(clip) = clip.as_display_object().and_then(|o| o.as_movie_clip()) {
|
if let Some(clip) = clip.as_display_object().and_then(|o| o.as_movie_clip()) {
|
||||||
// TODO(moulins): we need Str::parse for avoiding allocation here.
|
// TODO(moulins): we need WStr::parse for avoiding allocation here.
|
||||||
let frame = frame.to_string();
|
let frame = frame.to_string();
|
||||||
if let Ok(frame) = frame.parse().map(f64_to_wrapping_i32) {
|
if let Ok(frame) = frame.parse().map(f64_to_wrapping_i32) {
|
||||||
// First try to parse as a frame number.
|
// First try to parse as a frame number.
|
||||||
|
|
|
@ -294,11 +294,14 @@ pub fn as_set_prop_flags<'gc>(
|
||||||
),
|
),
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let props = v.coerce_to_string(activation)?;
|
let props = v.coerce_to_string(activation)?;
|
||||||
if props.as_str().contains(',') {
|
if props.contains(b',') {
|
||||||
for prop_name in props.as_str().split(',') {
|
for prop_name in props.split(b',') {
|
||||||
object.set_attributes(
|
object.set_attributes(
|
||||||
activation.context.gc_context,
|
activation.context.gc_context,
|
||||||
Some(AvmString::new(activation.context.gc_context, prop_name)),
|
Some(AvmString::new_ucs2(
|
||||||
|
activation.context.gc_context,
|
||||||
|
prop_name.into(),
|
||||||
|
)),
|
||||||
set_attributes,
|
set_attributes,
|
||||||
clear_attributes,
|
clear_attributes,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::add_field_accessors;
|
use crate::add_field_accessors;
|
||||||
use crate::avm1::{Object, ScriptObject, TObject};
|
use crate::avm1::{Object, ScriptObject, TObject};
|
||||||
use crate::impl_custom_object;
|
use crate::impl_custom_object;
|
||||||
|
use crate::string::WStr;
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -13,24 +14,26 @@ pub enum BevelFilterType {
|
||||||
Full,
|
Full,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for BevelFilterType {
|
impl From<WStr<'_>> for BevelFilterType {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: WStr<'_>) -> Self {
|
||||||
match value {
|
if value == b"inner" {
|
||||||
"inner" => BevelFilterType::Inner,
|
BevelFilterType::Inner
|
||||||
"outer" => BevelFilterType::Outer,
|
} else if value == b"outer" {
|
||||||
"full" => BevelFilterType::Full,
|
BevelFilterType::Outer
|
||||||
_ => BevelFilterType::Full,
|
} else {
|
||||||
|
BevelFilterType::Full
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BevelFilterType> for &str {
|
impl From<BevelFilterType> for WStr<'static> {
|
||||||
fn from(v: BevelFilterType) -> Self {
|
fn from(v: BevelFilterType) -> WStr<'static> {
|
||||||
match v {
|
let s: &[u8] = match v {
|
||||||
BevelFilterType::Inner => "inner",
|
BevelFilterType::Inner => b"inner",
|
||||||
BevelFilterType::Outer => "outer",
|
BevelFilterType::Outer => b"outer",
|
||||||
BevelFilterType::Full => "full",
|
BevelFilterType::Full => b"full",
|
||||||
}
|
};
|
||||||
|
WStr::from_units(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::add_field_accessors;
|
use crate::add_field_accessors;
|
||||||
use crate::avm1::{Object, ScriptObject, TObject};
|
use crate::avm1::{Object, ScriptObject, TObject};
|
||||||
use crate::impl_custom_object;
|
use crate::impl_custom_object;
|
||||||
|
use crate::string::WStr;
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -14,32 +15,29 @@ pub enum DisplacementMapFilterMode {
|
||||||
Color,
|
Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for DisplacementMapFilterMode {
|
impl From<WStr<'_>> for DisplacementMapFilterMode {
|
||||||
fn from(v: &str) -> DisplacementMapFilterMode {
|
fn from(v: WStr<'_>) -> DisplacementMapFilterMode {
|
||||||
match v {
|
if v == b"clamp" {
|
||||||
"wrap" => DisplacementMapFilterMode::Wrap,
|
DisplacementMapFilterMode::Clamp
|
||||||
"clamp" => DisplacementMapFilterMode::Clamp,
|
} else if v == b"ignore" {
|
||||||
"ignore" => DisplacementMapFilterMode::Ignore,
|
DisplacementMapFilterMode::Ignore
|
||||||
"color" => DisplacementMapFilterMode::Color,
|
} else if v == b"color" {
|
||||||
_ => DisplacementMapFilterMode::Wrap,
|
DisplacementMapFilterMode::Color
|
||||||
|
} else {
|
||||||
|
DisplacementMapFilterMode::Wrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DisplacementMapFilterMode> for &str {
|
impl From<DisplacementMapFilterMode> for WStr<'static> {
|
||||||
fn from(v: DisplacementMapFilterMode) -> Self {
|
fn from(v: DisplacementMapFilterMode) -> Self {
|
||||||
match v {
|
let s: &[u8] = match v {
|
||||||
DisplacementMapFilterMode::Wrap => "wrap",
|
DisplacementMapFilterMode::Wrap => b"wrap",
|
||||||
DisplacementMapFilterMode::Clamp => "clamp",
|
DisplacementMapFilterMode::Clamp => b"clamp",
|
||||||
DisplacementMapFilterMode::Ignore => "ignore",
|
DisplacementMapFilterMode::Ignore => b"ignore",
|
||||||
DisplacementMapFilterMode::Color => "color",
|
DisplacementMapFilterMode::Color => b"color",
|
||||||
}
|
};
|
||||||
}
|
WStr::from_units(s)
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DisplacementMapFilterMode> for String {
|
|
||||||
fn from(v: DisplacementMapFilterMode) -> Self {
|
|
||||||
Into::<&str>::into(v).to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue