Generate native core discovery from typed dispatch contracts
This commit is contained in:
@@ -48,8 +48,9 @@ pub fn client_rs(name: &str, doc: &Value) -> Result<String, String> {
|
||||
let mut result = vec![];
|
||||
for method in methods.as_array().into_iter().flatten() {
|
||||
let wire = method["name"].as_str().ok_or("method name missing")?;
|
||||
let ident = syn::parse_str::<syn::Ident>(wire)
|
||||
.or_else(|_| syn::parse_str::<syn::Ident>(&format!("r#{wire}")))
|
||||
let rust_name = wire.replace('.', "_");
|
||||
let ident = syn::parse_str::<syn::Ident>(&rust_name)
|
||||
.or_else(|_| syn::parse_str::<syn::Ident>(&format!("r#{rust_name}")))
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut rs = method["result"]["schema"].clone();
|
||||
local_refs(&mut rs);
|
||||
|
||||
+46
-1
@@ -204,7 +204,7 @@ fn supported(sender: &Value, document: &Value, seen: &mut HashSet<usize>) -> Res
|
||||
supported(child, document, seen)?;
|
||||
}
|
||||
}
|
||||
"additionalProperties" if value.is_boolean() => (),
|
||||
"additionalProperties" => supported(value, document, seen)?,
|
||||
"enum"
|
||||
if value
|
||||
.as_array()
|
||||
@@ -447,6 +447,15 @@ fn compare_variants(
|
||||
{
|
||||
let error = if let Some(other) = receiver["properties"].get(key) {
|
||||
subset(child, other, sender_doc, receiver_doc, active).err()
|
||||
} else if receiver["additionalProperties"].is_object() {
|
||||
subset(
|
||||
child,
|
||||
&receiver["additionalProperties"],
|
||||
sender_doc,
|
||||
receiver_doc,
|
||||
active,
|
||||
)
|
||||
.err()
|
||||
} else if receiver["additionalProperties"] == false {
|
||||
Some((
|
||||
format!(
|
||||
@@ -471,6 +480,42 @@ fn compare_variants(
|
||||
));
|
||||
}
|
||||
}
|
||||
// A typed dictionary can send arbitrary keys, unlike a struct's
|
||||
// closed set of output fields. Check both receiver named fields
|
||||
// and its catch-all value contract.
|
||||
if let Some(extra) = sender.get("additionalProperties").filter(|v| v.is_object()) {
|
||||
let mut key = "extra".to_string();
|
||||
while sender["properties"].get(&key).is_some()
|
||||
|| receiver["properties"].get(&key).is_some()
|
||||
{
|
||||
key.push('!');
|
||||
}
|
||||
let catch_all = receiver
|
||||
.get("additionalProperties")
|
||||
.unwrap_or(&Value::Bool(true));
|
||||
let targets = receiver["properties"]
|
||||
.as_object()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|(key, _)| sender["properties"].get(*key).is_none())
|
||||
.chain(std::iter::once((&key, catch_all)));
|
||||
for (key, target) in targets {
|
||||
if let Err((message, example)) =
|
||||
subset(extra, target, sender_doc, receiver_doc, active)
|
||||
{
|
||||
let mut object = sample(sender, sender_doc, &mut HashSet::new());
|
||||
if let (Some(Value::Object(object)), Some(value)) = (&mut object, example) {
|
||||
object.insert(key.clone(), value);
|
||||
} else {
|
||||
object = None;
|
||||
}
|
||||
return Err((
|
||||
format!("the dictionary field {key:?} is incompatible: {message}"),
|
||||
object,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"array" => {
|
||||
if let Err((message, example)) = subset(
|
||||
|
||||
Reference in New Issue
Block a user