tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 660Markdown 302TOML 157RON 312382 Sutichaykuna

⎇ main shared/foreign-lottie/src/schema/assets/image.rs Rust · 118 siq'ikuna · 3.2 KB Ñawpa willay Pi imata llamkarqan ch'uya

chore: refresco desde el monorepo — 27 crates nuevos (anim, lottie, svg, mesh, image, layer, test, wire-view, widgets rag-sidebar/router/lazy-list/rive-button) y sync de los 95 existentes 93253cc22 · Sergio ·

1// Copyright 2024 the Velato Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use crate::schema::helpers::slottable_object::SlottableObject;
5
6use super::file_asset::FileAsset;
7use serde::de::Deserializer;
8use serde::{Deserialize, Serialize, Serializer};
9
10/// External image
11#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
12pub struct Image {
13    /// File asset properties
14    #[serde(flatten)]
15    pub file_asset: FileAsset,
16    /// Slottable object properties
17    #[serde(flatten)]
18    pub slottable_object: SlottableObject,
19    /// Width of the image
20    #[serde(rename = "w")]
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub width: Option<f64>,
23    /// Height of the image
24    #[serde(rename = "h")]
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub height: Option<f64>,
27    /// Mark as part of an image sequence if present.
28    #[serde(
29        rename = "t",
30        deserialize_with = "seq_from_str",
31        serialize_with = "seq_to_str",
32        default
33    )]
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub sequence: Option<bool>,
36}
37
38pub fn seq_from_str<'de, D>(deserializer: D) -> Result<Option<bool>, D::Error>
39where
40    D: Deserializer<'de>,
41{
42    let v = String::deserialize(deserializer)?;
43    if v == *"seq" {
44        Ok(Some(true))
45    } else {
46        Ok(None)
47    }
48}
49
50// Function signature must match Serde's Serialize trait, so need to suppress Clippy.
51pub fn seq_to_str<S>(v: &Option<bool>, serializer: S) -> Result<S::Ok, S::Error>
52where
53    S: Serializer,
54{
55    match v {
56        Some(true) => Serializer::serialize_str(serializer, "seq"),
57        Some(false) => Serializer::serialize_str(serializer, ""),
58        None => unimplemented!("serializer should skip if none"),
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::Image;
65    use crate::schema::{
66        assets::{asset::Asset, file_asset::FileAsset},
67        helpers::{
68            int_boolean::BoolInt, slottable_object::SlottableObject, visual_object::VisualObject,
69        },
70    };
71    use serde_json::json;
72    use std::sync::LazyLock;
73
74    static JSON: LazyLock<serde_json::Value> = LazyLock::new(|| {
75        json!(
76            {
77                "id": "my image",
78                "h": 512,
79                "w": 512,
80                "e": 1,
81                "p": "data:image/png;base64,..."
82            }
83        )
84    });
85    static IMAGE: LazyLock<Image> = LazyLock::new(|| Image {
86        slottable_object: SlottableObject::default(),
87        file_asset: FileAsset {
88            asset: Asset {
89                id: "my image".to_string(),
90                visual_object: VisualObject {
91                    name: None,
92                    match_name: None,
93                },
94            },
95            dir: None,
96            file_name: "data:image/png;base64,...".to_string(),
97            embedded: Some(BoolInt::True),
98        },
99        height: Some(512.0),
100        width: Some(512.0),
101        sequence: None,
102    });
103
104    #[test]
105    fn test_deserialize() {
106        let actual = serde_json::from_value(JSON.to_owned());
107
108        match actual {
109            Ok(actual) => assert_eq!(*IMAGE, actual),
110            Err(e) => panic!("{e}"),
111        }
112    }
113
114    #[test]
115    fn test_can_serialize() {
116        serde_json::to_value(&*IMAGE).unwrap();
117    }
118}