补充 Filled 图片类型反序列化校验

新增字段级 amount 反序列化校验,拒绝非有限和越界值

保持现有 JSON 形状与 schema 版本,不引入迁移

增加非法填充量回归测试
This commit is contained in:
2026-08-18 16:20:13 +08:00
parent e262fd2a60
commit 11f7efa090
@@ -6,7 +6,7 @@ use crate::ui_editor::resource::sprite::SpriteAsset;
use crate::ui_editor::utils::SpriteAssetId;
use nalgebra::Vector2;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde::{de::Deserializer, Deserialize, Serialize};
use ts_rs::TS;
use typed_floats::tf32::StrictlyPositiveFinite;
@@ -80,6 +80,15 @@ fn validate_fill_amount(amount: f32) -> Result<(), ComponentValueError> {
Ok(())
}
fn deserialize_fill_amount<'de, D>(deserializer: D) -> Result<f32, D::Error>
where
D: Deserializer<'de>,
{
let amount = f32::deserialize(deserializer)?;
validate_fill_amount(amount).map_err(serde::de::Error::custom)?;
Ok(amount)
}
#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Serialize, TS)]
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
pub enum ImageType {
@@ -101,6 +110,7 @@ pub enum ImageType {
Filled {
preserve_aspect: bool,
method: FillMethod,
#[serde(deserialize_with = "deserialize_fill_amount")]
amount: f32,
},
}
@@ -225,6 +235,42 @@ impl ImageComponent {
}
}
#[cfg(test)]
mod tests {
use super::{FillMethod, HorizontalFillOrigin, ImageType};
#[test]
fn filled_amount_is_validated_when_deserialized() {
let valid = serde_json::json!({
"Filled": {
"preserve_aspect": false,
"method": { "Horizontal": "Left" },
"amount": 0.5
}
});
let image_type: ImageType = serde_json::from_value(valid).expect("valid fill amount");
assert!(matches!(
image_type,
ImageType::Filled {
method: FillMethod::Horizontal(HorizontalFillOrigin::Left),
amount: 0.5,
..
}
));
for amount in ["-0.1", "1.1", "null"] {
let value = serde_json::json!({
"Filled": {
"preserve_aspect": false,
"method": { "Horizontal": "Left" },
"amount": serde_json::from_str::<serde_json::Value>(amount).unwrap()
}
});
assert!(serde_json::from_value::<ImageType>(value).is_err());
}
}
}
impl Default for ImageComponent {
fn default() -> Self {
Self::new()