use crate::e2e::codegen::field_skip::FieldSkip;
use crate::e2e::field_access::FieldResolver;
const COUNT_SUFFIXES: [&str; 3] = ["length", "count", "size"];
pub(super) fn json_bridged_traversal_skip(field_resolver: &FieldResolver, field: Option<&str>) -> Option<String> {
let field = field.filter(|f| !f.is_empty())?;
let bridged = field_resolver.swift_json_bridged_traversal_prefix(field)?;
Some(skip_line(FieldSkip::CountOnJsonBridgedLeafInSwift, &bridged))
}
pub(super) fn non_countable_leaf_count_skip(field_resolver: &FieldResolver, field: Option<&str>) -> Option<String> {
let field = field?;
let collection = COUNT_SUFFIXES
.iter()
.find_map(|suffix| field.strip_suffix(&format!(".{suffix}")))?;
if collection.is_empty() || field_resolver.leaf_is_vec_via_swift_map(field_resolver.resolve(collection)) {
return None;
}
Some(skip_line(FieldSkip::CountOnJsonBridgedLeafInSwift, field))
}
pub(super) fn unspellable_collection_emptiness_skip(
field_resolver: &FieldResolver,
field: Option<&str>,
) -> Option<String> {
let field = field.filter(|f| !f.is_empty())?;
let resolved = field_resolver.resolve(field);
let is_collection = field_resolver.is_array(field)
|| field_resolver.is_array(resolved)
|| field_resolver.is_collection_root(field)
|| field_resolver.is_collection_root(resolved);
if !is_collection || !field_resolver.leaf_is_json_bridged_via_swift_map(resolved) {
return None;
}
Some(skip_line(FieldSkip::CountOnJsonBridgedLeafInSwift, field))
}
pub(super) fn non_countable_leaf_skip_line(field: Option<&str>) -> String {
skip_line(
FieldSkip::CountOnJsonBridgedLeafInSwift,
field
.filter(|f| !f.is_empty())
.unwrap_or(super::assertions::BARE_RESULT_TOKEN),
)
}
pub(super) fn leaf_getter_is_optional(field_resolver: &FieldResolver, field: Option<&str>) -> bool {
field
.filter(|f| !f.is_empty())
.and_then(|f| field_resolver.swift_leaf_getter_is_optional(f))
.unwrap_or(false)
}
fn skip_line(kind: FieldSkip, field: &str) -> String {
format!(" // skipped: {}\n", kind.message(field))
}
pub(super) fn mixed_map_then_vec_traversal_skip(field: &str) -> String {
skip_line(FieldSkip::MixedMapThenVecTraversalInSwift, field)
}
#[cfg(test)]
mod mixed_map_then_vec_tests {
use super::json_bridged_traversal_skip;
use crate::e2e::field_access::{FieldResolver, SwiftFirstClassMap};
use std::collections::{HashMap, HashSet};
fn ir_backed_resolver() -> FieldResolver {
let swift_first_class_map = SwiftFirstClassMap {
json_bridged_field_names: HashSet::from(["labels".to_string()]),
..SwiftFirstClassMap::default()
};
FieldResolver::new_with_swift_first_class(
&HashMap::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
&HashMap::new(),
swift_first_class_map,
)
}
#[test]
fn ir_backed_json_bridged_map_field_is_refused_before_an_accessor_is_built() {
let resolver = ir_backed_resolver();
let skip = json_bridged_traversal_skip(&resolver, Some("labels[key].items[0]"));
let Some(skip) = skip else {
panic!("IR-backed json-bridged map field must be refused before accessor-building");
};
assert!(skip.contains("'labels'"), "got: {skip}");
}
#[test]
fn opaque_resolver_does_not_refuse_here_the_gap_is_closed_downstream() {
let empty = HashSet::new();
let resolver = FieldResolver::new(&HashMap::new(), &empty, &empty, &empty, &empty);
let skip = json_bridged_traversal_skip(&resolver, Some("labels[key].items[0]"));
assert!(
skip.is_none(),
"an IR-less resolver has no positive fact to refuse on; got: {skip:?}"
);
}
}