use crate::asset::{Costume, Sound};
use crate::prelude::*;
use crate::string_hashmap::StringHashMap;
use crate::{block::Block, broadcast::Broadcast, comment::Comment, list::List, variable::Variable};
use utils::json_to_unexpected;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Target {
pub name: Text,
pub variables: StringHashMap<Variable>,
pub lists: StringHashMap<List>,
pub broadcasts: StringHashMap<Broadcast>,
pub blocks: StringHashMap<Block>,
pub comments: StringHashMap<Comment>,
pub current_costume: Int,
pub costumes: Vec<Costume>,
pub sounds: Vec<Sound>,
pub layer_order: Int,
pub volume: Number,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Stage {
#[serde(flatten)]
pub target: Target,
pub tempo: Number,
pub video_state: VideoState,
pub video_transparency: Number,
pub text_to_speech_language: Option<Json>,
pub is_stage: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Sprite {
#[serde(flatten)]
pub target: Target,
pub visible: bool,
pub x: Number,
pub y: Number,
pub size: Number,
pub direction: Number,
pub draggable: bool,
pub rotation_style: RotationStyle,
pub is_stage: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(untagged)]
pub enum SpriteOrStage {
Stage(Stage),
Sprite(Sprite),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum VideoState {
#[serde(rename = "on")]
On,
#[serde(rename = "off")]
Off,
#[serde(rename = "on-flipped")]
OnFlipped,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
pub enum RotationStyle {
#[serde(rename = "all around")]
AllAround,
#[serde(rename = "left right")]
LeftRight,
#[serde(rename = "don't rotate")]
DontRotate,
}
impl<'de> Deserialize<'de> for SpriteOrStage {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
let object_j = Json::deserialize(deserializer)?;
let object = match &object_j {
Json::Object(o) => o,
o => {
return Err(<D::Error as Error>::invalid_type(
json_to_unexpected(o),
&"sprite or stage map, tagged with `isStage` key",
))
}
};
let Some(is_stage) = object.get("isStage") else {
return Err(
<D::Error as Error>::missing_field("isStage")
)
};
let is_stage = match is_stage {
&Json::Bool(b) => b,
o => {
return Err(<D::Error as Error>::invalid_value(
json_to_unexpected(o),
&"`isStage` key must be the type `bool`",
))
}
};
if is_stage {
Ok(SpriteOrStage::Stage(
serde_json::from_value(object_j).map_err(<D::Error as Error>::custom)?,
))
} else {
Ok(SpriteOrStage::Sprite(
serde_json::from_value(object_j).map_err(<D::Error as Error>::custom)?,
))
}
}
}