KCL None needs more specific serialization (#3720)
Previously, many KCL values could be deserialized as KCL None values. This isn't good -- the only thing you should be able to possibly deserialize as KCL None is KCL None. Solution was to add a private field in KCL None, serialize it with a special magic number value, and then check for that magic number when deserializing
This commit is contained in:
@ -9,6 +9,8 @@ use crate::{
|
|||||||
executor::{KclValue, SourceRange, UserVal},
|
executor::{KclValue, SourceRange, UserVal},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const KCL_NONE_ID: &str = "KCL_NONE_ID";
|
||||||
|
|
||||||
/// KCL value for an optional parameter which was not given an argument.
|
/// KCL value for an optional parameter which was not given an argument.
|
||||||
/// (remember, parameters are in the function declaration,
|
/// (remember, parameters are in the function declaration,
|
||||||
/// arguments are in the function call/application).
|
/// arguments are in the function call/application).
|
||||||
@ -20,6 +22,45 @@ pub struct KclNone {
|
|||||||
// TODO: Convert this to be an Option<SourceRange>.
|
// TODO: Convert this to be an Option<SourceRange>.
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
|
#[serde(deserialize_with = "deser_private")]
|
||||||
|
#[ts(skip)]
|
||||||
|
#[schemars(skip)]
|
||||||
|
__private: Private,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KclNone {
|
||||||
|
pub fn new(start: usize, end: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
__private: Private {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Bake, Default)]
|
||||||
|
#[databake(path = kcl_lib::ast::types)]
|
||||||
|
struct Private;
|
||||||
|
|
||||||
|
impl Serialize for Private {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(KCL_NONE_ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deser_private<'de, D>(deserializer: D) -> Result<Private, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s = String::deserialize(deserializer)?;
|
||||||
|
if s == KCL_NONE_ID {
|
||||||
|
Ok(Private {})
|
||||||
|
} else {
|
||||||
|
Err(serde::de::Error::custom("not a KCL none"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&KclNone> for SourceRange {
|
impl From<&KclNone> for SourceRange {
|
||||||
@ -57,3 +98,24 @@ impl KclNone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn other_types_will_not_deserialize() {
|
||||||
|
// This shouldn't deserialize into a KCL None,
|
||||||
|
// because it's missing the special Private tag.
|
||||||
|
let j = r#"{"start": 0, "end": 0}"#;
|
||||||
|
let _e = serde_json::from_str::<KclNone>(j).unwrap_err();
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn serialize_then_deserialize() {
|
||||||
|
// Serializing, then deserializing a None should produce the same value.
|
||||||
|
let before = KclNone::default();
|
||||||
|
let j = serde_json::to_string_pretty(&before).unwrap();
|
||||||
|
let after: KclNone = serde_json::from_str(&j).unwrap();
|
||||||
|
assert_eq!(before, after);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2080,10 +2080,7 @@ fn assign_args_to_params(
|
|||||||
if param.optional {
|
if param.optional {
|
||||||
// If the corresponding parameter is optional,
|
// If the corresponding parameter is optional,
|
||||||
// then it's fine, the user doesn't need to supply it.
|
// then it's fine, the user doesn't need to supply it.
|
||||||
let none = KclNone {
|
let none = KclNone::new(param.identifier.start, param.identifier.end);
|
||||||
start: param.identifier.start,
|
|
||||||
end: param.identifier.end,
|
|
||||||
};
|
|
||||||
fn_memory.add(
|
fn_memory.add(
|
||||||
¶m.identifier.name,
|
¶m.identifier.name,
|
||||||
KclValue::from(&none),
|
KclValue::from(&none),
|
||||||
|
|||||||
Reference in New Issue
Block a user