From d49143fc7b28b274cec37bc08e4454bef5da71ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 18 Aug 2026 16:25:25 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=20BestFitFontSize=20?= =?UTF-8?q?=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过自定义反序列化恢复 min 不大于 max 的构造不变量 保持现有 JSON 形状、生成绑定和 schema 版本,不引入迁移 增加无效字体范围回归测试 --- .../src-tauri/src/ui_editor/component/text.rs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs index 092e8fc0c..46291e831 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs @@ -2,7 +2,7 @@ use crate::ui_editor::component::common::error::ComponentValueError; use crate::ui_editor::resource::sprite::{Color, WHITE}; use crate::ui_editor::utils::FontAssetId; use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +use serde::{de::Deserializer, Deserialize, Serialize}; use std::num::NonZeroU32; use ts_rs::TS; use typed_floats::tf32::StrictlyPositiveFinite; @@ -44,13 +44,29 @@ pub enum VerticalTextOverflow { Overflow, } -#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Serialize, TS)] +#[derive(Clone, Copy, Debug, JsonSchema, PartialEq, Serialize, TS)] #[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))] pub struct BestFitFontSize { min: NonZeroU32, max: NonZeroU32, } +impl<'de> Deserialize<'de> for BestFitFontSize { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct RawBestFitFontSize { + min: NonZeroU32, + max: NonZeroU32, + } + + let raw = RawBestFitFontSize::deserialize(deserializer)?; + Self::new(raw.min, raw.max).map_err(serde::de::Error::custom) + } +} + impl BestFitFontSize { pub fn new(min: NonZeroU32, max: NonZeroU32) -> Result { if min > max { @@ -129,6 +145,29 @@ impl Default for TextComponent { } } +#[cfg(test)] +mod best_fit_tests { + use super::{BestFitFontSize, FontSizing}; + + #[test] + fn best_fit_font_size_is_validated_when_deserialized() { + let valid: BestFitFontSize = + serde_json::from_value(serde_json::json!({ "min": 12, "max": 24 })) + .expect("valid font-size range"); + assert_eq!(valid.min().get(), 12); + assert_eq!(valid.max().get(), 24); + + assert!(serde_json::from_value::( + serde_json::json!({ "min": 24, "max": 12 }), + ) + .is_err()); + assert!(serde_json::from_value::( + serde_json::json!({ "BestFit": { "min": 24, "max": 12 } }), + ) + .is_err()); + } +} + #[cfg(test)] mod tests { use super::*;