Standardize unimplemented API failures
This commit is contained in:
@@ -175,6 +175,12 @@ RUST_KEYWORDS = {
|
||||
"macro", "override", "priv", "typeof", "unsized", "virtual", "yield", "try",
|
||||
}
|
||||
|
||||
FAKE_BODY = re.compile(
|
||||
r"\b(?:Default::default|unwrap_or_default|Vec::new|String::new|UUID::nil|Uuid::nil|"
|
||||
r"(?:std::iter|stream)::empty)\s*\(|\b(?:return\s+)?(?:false|true|0)\s*;|"
|
||||
r"\b(?:Ok|Some)\(\s*(?:false|true|0|None|Vec::new\(\)|String::new\(\))\s*\)"
|
||||
)
|
||||
|
||||
|
||||
def snake(name: str) -> str:
|
||||
name = name.lstrip("@").replace("#", "_")
|
||||
@@ -345,6 +351,60 @@ def render_tsv(fieldnames: list[str], rows: list[dict[str, str]]) -> str:
|
||||
return output.getvalue()
|
||||
|
||||
|
||||
def function_bodies(text: str) -> list[str]:
|
||||
bodies = []
|
||||
function = re.compile(r"(?m)^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:async\s+)?fn\s+[A-Za-z_][A-Za-z0-9_]*")
|
||||
for match in function.finditer(text):
|
||||
brace = text.find("{", match.end())
|
||||
semicolon = text.find(";", match.end())
|
||||
if brace < 0 or (semicolon >= 0 and semicolon < brace):
|
||||
continue
|
||||
depth = 0
|
||||
quote = None
|
||||
escaped = False
|
||||
index = brace
|
||||
while index < len(text):
|
||||
char = text[index]
|
||||
if quote:
|
||||
if escaped:
|
||||
escaped = False
|
||||
elif char == "\\":
|
||||
escaped = True
|
||||
elif char == quote:
|
||||
quote = None
|
||||
elif char == '"':
|
||||
quote = char
|
||||
elif text.startswith("//", index):
|
||||
newline = text.find("\n", index)
|
||||
index = len(text) if newline < 0 else newline
|
||||
elif text.startswith("/*", index):
|
||||
end = text.find("*/", index + 2)
|
||||
index = len(text) if end < 0 else end + 1
|
||||
elif char == "{":
|
||||
depth += 1
|
||||
elif char == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
bodies.append(text[brace + 1 : index])
|
||||
break
|
||||
index += 1
|
||||
else:
|
||||
raise ValueError("unbalanced generated Rust function body")
|
||||
return bodies
|
||||
|
||||
|
||||
def validate_generated_shims() -> None:
|
||||
for path in sorted((ROOT / "crates").glob("*/src/generated*.rs")):
|
||||
text = path.read_text()
|
||||
if re.search(r"#\[derive\([^]]*\bDefault\b", text):
|
||||
raise ValueError(f"generated shim derives a plausible Default: {path.relative_to(ROOT)}")
|
||||
for body in function_bodies(text):
|
||||
if FAKE_BODY.search(body):
|
||||
raise ValueError(f"generated shim returns a plausible fallback: {path.relative_to(ROOT)}")
|
||||
if not any(marker in body for marker in ("unimplemented_api!", "not_implemented(", "NotImplemented::new(")):
|
||||
raise ValueError(f"generated shim function does not use the standardized failure: {path.relative_to(ROOT)}")
|
||||
|
||||
|
||||
def build_type_rows(catalog: dict) -> tuple[list[dict[str, str]], dict[str, str]]:
|
||||
rows = []
|
||||
resolved: dict[str, str] = {}
|
||||
@@ -629,6 +689,8 @@ def build_member_rows(catalog: dict, mapper: Mapper) -> list[dict[str, str]]:
|
||||
|
||||
|
||||
def validate(catalog: dict, type_rows: list[dict[str, str]], member_rows: list[dict[str, str]], mapper: Mapper) -> None:
|
||||
validate_generated_shims()
|
||||
|
||||
def unique(rows: list[dict[str, str]], field: str) -> None:
|
||||
duplicates = [value for value, count in Counter(row[field] for row in rows).items() if count > 1]
|
||||
if duplicates:
|
||||
@@ -711,7 +773,8 @@ def coverage_report(catalog: dict, type_rows: list[dict[str, str]], member_rows:
|
||||
f"- C# public members mapped: **{len(member_rows):,} / {catalog['summary']['public_member_count']:,} (100%)**",
|
||||
f"- External signature types resolved: **{len(external):,} / {len(catalog['external_types']):,} (100%)**",
|
||||
"- Duplicate C# IDs: **0**", "- Duplicate Rust destinations: **0**", "- Stale or missing catalog IDs: **0**",
|
||||
"- Unresolved referenced types: **0**", "- Platform-specific mappings: **0**", "",
|
||||
"- Unresolved referenced types: **0**", "- Platform-specific mappings: **0**",
|
||||
"- Plausible generated fallback bodies/default derives: **0**", "",
|
||||
"## Assembly representatives", "", "| Assembly | Rust crate | Members | Representative mapping |", "|---|---|---:|---|",
|
||||
]
|
||||
for assembly in catalog["assemblies"]:
|
||||
@@ -761,6 +824,8 @@ def self_check() -> None:
|
||||
assert split_top_level("A<B, C<D, E>>, F") == ["A<B, C<D, E>>", "F"]
|
||||
assert type_parts("A<B<C>, D>.Nested[]") == ("A.Nested", ["B<C>", "D"], "[]")
|
||||
assert snake("HTTPRequest2") == "http_request2"
|
||||
assert function_bodies("pub fn value() -> bool { false }") == [" false "]
|
||||
assert FAKE_BODY.search(function_bodies("pub fn value() -> bool { false; }")[0])
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
@@ -128,7 +128,7 @@ def render_type(name: str, kind: str, arity: int, csharp_name: str, indent: str)
|
||||
declaration = f"pub struct {rust_name}{params}" + (";" if not marker else f"{marker};")
|
||||
return [
|
||||
f"{indent}/// `{kind}` shim for C# `{csharp_name}`; members remain intentionally unimplemented.",
|
||||
f"{indent}#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]",
|
||||
f"{indent}#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]",
|
||||
f"{indent}{declaration}",
|
||||
f"{indent}impl{('<' + ', '.join(f'T{i}' for i in range(arity)) + '>') if arity else ''} {rust_name}{('<' + ', '.join(f'T{i}' for i in range(arity)) + '>') if arity else ''} {{",
|
||||
f"{indent} pub const CSHARP_NAME: &'static str = \"{csharp_name}\";",
|
||||
|
||||
Reference in New Issue
Block a user