use crate::prelude::*;
use utils::{deserialize_json_str, serialize_json_str};
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Block {
pub opcode: OpCode<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub comment: Option<Id>,
pub next: Option<Id>,
pub parent: Option<Id>,
pub inputs: StringHashMap<BlockInput>,
pub fields: StringHashMap<BlockField>,
pub shadow: bool,
pub top_level: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mutation: Option<BlockMutation>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub x: Option<Number>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub y: Option<Number>,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct BlockInput {
pub shadow: ShadowInputType,
pub inputs: Vec<Option<IdOrValue>>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum IdOrValue {
Id(Id),
Value(BlockInputValue),
}
#[derive(Debug, Clone, PartialEq)]
pub enum BlockField {
WithId {
value: Value,
id: Option<Id>,
},
NoId {
value: Value,
},
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BlockMutation {
tag_name: String,
children: [(); 0],
#[serde(flatten)]
pub mutation_enum: BlockMutationEnum,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BlockMutationEnum {
ProceduresPrototype {
proccode: String,
#[serde(
deserialize_with = "deserialize_json_str",
serialize_with = "serialize_json_str"
)]
argumentids: Vec<Id>,
#[serde(
deserialize_with = "deserialize_json_str",
serialize_with = "serialize_json_str"
)]
argumentnames: Vec<Name>,
#[serde(
deserialize_with = "deserialize_json_str",
serialize_with = "serialize_json_str"
)]
argumentdefaults: Vec<ValueWithBool>,
#[serde(
deserialize_with = "deserialize_json_str",
serialize_with = "serialize_json_str"
)]
warp: Option<bool>,
},
ProceduresCall {
proccode: String,
#[serde(
deserialize_with = "deserialize_json_str",
serialize_with = "serialize_json_str"
)]
argumentids: Vec<Id>,
#[serde(
deserialize_with = "deserialize_json_str",
serialize_with = "serialize_json_str"
)]
warp: Option<bool>,
},
ControlStop {
#[serde(
deserialize_with = "deserialize_json_str",
serialize_with = "serialize_json_str"
)]
hasnext: bool,
},
}
#[derive(Debug, Default, Clone, PartialEq, Deserialize_repr, Serialize_repr)]
#[repr(u8)]
pub enum ShadowInputType {
Shadow = 1,
#[default]
NoShadow = 2,
ShadowObscured = 3,
}
#[derive(Debug, Clone, PartialEq)]
pub enum BlockInputValue {
Number {
value: Value,
},
PositiveNumber {
value: Value,
},
PositiveInteger {
value: Value,
},
Integer {
value: Value,
},
Angle {
value: Value,
},
Color {
value: Value,
},
String {
value: Value,
},
Broadcast {
name: Name,
id: Id,
},
Variable {
name: Name,
id: Id,
x: Option<Number>,
y: Option<Number>,
},
List {
name: Name,
id: Id,
x: Option<Number>,
y: Option<Number>,
},
}
impl Default for Block {
fn default() -> Self {
Block {
opcode: OpCode::default(),
comment: None,
next: None,
parent: None,
inputs: StringHashMap::default(),
fields: StringHashMap::default(),
shadow: false,
top_level: true,
mutation: None,
x: Some(0.into()),
y: Some(0.into()),
}
}
}
impl BlockInput {
fn size_hint(&self) -> usize {
1 + self.inputs.len()
}
}
struct BlockInputVisitor;
impl<'de> Visitor<'de> for BlockInputVisitor {
type Value = BlockInput;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("list that is a block input")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
use serde::de::Error;
let shadow = seq.next_element::<ShadowInputType>()?.ok_or_else(|| {
A::Error::invalid_length(0, &"Expected 2 or more elements for block input")
})?;
let mut inputs = vec![];
while let Some(v) = seq.next_element::<Option<IdOrValue>>()? {
inputs.push(v)
}
Ok(BlockInput { shadow, inputs })
}
}
impl<'de> Deserialize<'de> for BlockInput {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(BlockInputVisitor)
}
}
impl Serialize for BlockInput {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeSeq;
let mut s = serializer.serialize_seq(Some(self.size_hint()))?;
s.serialize_element(&self.shadow)?;
for v in &self.inputs {
s.serialize_element(&v)?;
}
s.end()
}
}
impl BlockInputValue {
fn get_id(&self) -> u8 {
use BlockInputValue::*;
match self {
Number { value: _ } => 4,
PositiveNumber { value: _ } => 5,
PositiveInteger { value: _ } => 6,
Integer { value: _ } => 7,
Angle { value: _ } => 8,
Color { value: _ } => 9,
String { value: _ } => 10,
Broadcast { name: _, id: _ } => 11,
Variable {
name: _,
id: _,
x: _,
y: _,
} => 12,
List {
name: _,
id: _,
x: _,
y: _,
} => 13,
}
}
fn hint_size(&self) -> usize {
use BlockInputValue::*;
match self {
Number { value: _ } => 1,
PositiveNumber { value: _ } => 1,
PositiveInteger { value: _ } => 1,
Integer { value: _ } => 1,
Angle { value: _ } => 1,
Color { value: _ } => 1,
String { value: _ } => 1,
Broadcast { name: _, id: _ } => 2,
Variable {
name: _,
id: _,
x,
y,
} => {
let mut n = 2;
if x.is_some() {
n += 1
}
if y.is_some() {
n += 1
}
n
}
List {
name: _,
id: _,
x,
y,
} => {
let mut n = 2;
if x.is_some() {
n += 1
}
if y.is_some() {
n += 1
}
n
}
}
}
}
struct BlockInputValueVisitor;
impl<'de> Visitor<'de> for BlockInputValueVisitor {
type Value = BlockInputValue;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("list that is a block input value")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
use serde::de::Error;
use BlockInputValue::{
Angle, Broadcast, Color, Integer, List, Number as BlockInputNumber, PositiveInteger,
PositiveNumber, String, Variable,
};
fn seq_next_element_error<'de, T, A>(
seq: &mut A,
len: usize,
error: &str,
) -> Result<T, A::Error>
where
A: serde::de::SeqAccess<'de>,
T: Deserialize<'de>,
{
seq.next_element::<T>()?
.ok_or_else(|| A::Error::invalid_length(len, &error))
}
let vtype: u8 = seq_next_element_error(
&mut seq,
0,
"Expecting 2 or more elements for block input value with any Id",
)?;
let value = seq_next_element_error(
&mut seq,
1,
"Expecting 2 or more elements for block input value with any Id",
)?;
let res = match vtype {
4 => BlockInputNumber { value },
5 => PositiveNumber { value },
6 => PositiveInteger { value },
7 => Integer { value },
8 => Angle { value },
9 => Color { value },
10 => String { value },
11 => {
let id = seq_next_element_error(
&mut seq,
3,
"Expecting 3 or more elements for block input value with Id 11",
)?;
let name = match value {
Value::Text(s) => s,
Value::Number(_) => {
return Err(A::Error::invalid_value(
serde::de::Unexpected::Other("number"),
&"a string",
))
}
};
Broadcast { name, id }
}
12 => {
let id = seq_next_element_error(
&mut seq, 3,
"Expecting 3 or 5 or more elements for block input value with Id 12 - 13 inclusive"
)?;
let x = seq.next_element::<Number>()?;
let y = seq.next_element::<Number>()?;
let name = match value {
Value::Text(s) => s,
Value::Number(_) => {
return Err(A::Error::invalid_value(
serde::de::Unexpected::Other("number"),
&"a string",
))
}
};
Variable { name, id, x, y }
}
13 => {
let id = seq_next_element_error(
&mut seq, 3,
"Expecting 3 or 5 or more elements for block input value with Id 12 - 13 inclusive"
)?;
let x = seq.next_element::<Number>()?;
let y = seq.next_element::<Number>()?;
let name = match value {
Value::Text(s) => s,
Value::Number(_) => {
return Err(A::Error::invalid_value(
serde::de::Unexpected::Other("number"),
&"a string",
))
}
};
List { name, id, x, y }
}
v => {
return Err(A::Error::invalid_value(
serde::de::Unexpected::Unsigned(v.into()),
&"Expecting a type id between 4 - 13 inclusive",
))
}
};
Ok(res)
}
}
impl<'de> Deserialize<'de> for BlockInputValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(BlockInputValueVisitor)
}
}
impl Serialize for BlockInputValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeSeq;
use BlockInputValue::*;
let mut s = serializer.serialize_seq(Some(self.hint_size()))?;
s.serialize_element(&self.get_id())?;
match self {
Number { value }
| PositiveNumber { value }
| PositiveInteger { value }
| Integer { value }
| Angle { value }
| Color { value }
| String { value } => {
s.serialize_element(value)?;
}
Broadcast { name, id } => {
s.serialize_element(name)?;
s.serialize_element(id)?;
}
Variable { name, id, x, y } | List { name, id, x, y } => {
s.serialize_element(name)?;
s.serialize_element(id)?;
if let Some(x) = x {
s.serialize_element(x)?;
}
if let Some(y) = y {
s.serialize_element(y)?;
}
}
}
s.end()
}
}
impl BlockField {
#[inline(always)]
pub fn value(&self) -> &Value {
match self {
BlockField::WithId { value, id: _ } => value,
BlockField::NoId { value } => value,
}
}
#[inline(always)]
pub fn id(&self) -> Option<&Id> {
match self {
BlockField::WithId { value: _, id } => id.as_ref(),
BlockField::NoId { value: _ } => None,
}
}
}
struct BlockFieldVisitor;
impl<'de> Visitor<'de> for BlockFieldVisitor {
type Value = BlockField;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("sequence of values that is a blockfield")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
use serde::de::Error;
let value = seq
.next_element::<Value>()?
.ok_or_else(|| A::Error::invalid_length(1, &"length 1 or 2 for BlockField"))?;
let id = seq.next_element::<Option<Id>>()?;
Ok(match id {
Some(id) => BlockField::WithId { value, id },
None => BlockField::NoId { value },
})
}
}
impl<'de> Deserialize<'de> for BlockField {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(BlockFieldVisitor)
}
}
impl Serialize for BlockField {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeSeq;
match self {
BlockField::WithId { value, id } => {
let mut seq = serializer.serialize_seq(Some(2))?;
seq.serialize_element(value)?;
seq.serialize_element(id)?;
seq.end()
}
BlockField::NoId { value } => {
let mut seq = serializer.serialize_seq(Some(1))?;
seq.serialize_element(value)?;
seq.end()
}
}
}
}