Implement native inventory store and cache (#61)
All checks were successful
Native code generation / deterministic (push) Successful in 12m18s
Imaging and meshing gate / native (push) Successful in 4m2s
JPEG 2000 feature / linux (push) Successful in 2m34s
Native Rust workspace compile / compile (push) Successful in 4m4s
Skia feature / linux (push) Successful in 31m2s

This commit is contained in:
2026-08-10 00:06:28 +00:00
parent 0791e0a69e
commit eb7be428c6
16 changed files with 3131 additions and 1154 deletions

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""Audit issue 61's native inventory model, store, and cache boundary."""
from __future__ import annotations
from pathlib import Path
import re
import generate_api_shims
ROOT = Path(__file__).resolve().parents[1]
SOURCE = ROOT / "crates" / "libremetaverse" / "src" / "inventory.rs"
DOC = ROOT / "docs" / "inventory.md"
STORE_TESTS = ROOT / "tests" / "compat" / "tests" / "inventory_store_semantics.rs"
LINK_TESTS = ROOT / "tests" / "compat" / "tests" / "misclassified_link_semantics.rs"
STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(")
REQUIRED_TYPES = {
"T:LibreMetaverse.Inventory",
"T:LibreMetaverse.InventoryAnimation",
"T:LibreMetaverse.InventoryAttachment",
"T:LibreMetaverse.InventoryBase",
"T:LibreMetaverse.InventoryCallingCard",
"T:LibreMetaverse.InventoryCategory",
"T:LibreMetaverse.InventoryFolder",
"T:LibreMetaverse.InventoryGesture",
"T:LibreMetaverse.InventoryItem",
"T:LibreMetaverse.InventoryLSL",
"T:LibreMetaverse.InventoryLandmark",
"T:LibreMetaverse.InventoryMaterial",
"T:LibreMetaverse.InventoryNode",
"T:LibreMetaverse.InventoryNodeDictionary",
"T:LibreMetaverse.InventoryNotecard",
"T:LibreMetaverse.InventoryObject",
"T:LibreMetaverse.InventoryObjectAddedEventArgs",
"T:LibreMetaverse.InventoryObjectRemovedEventArgs",
"T:LibreMetaverse.InventoryObjectUpdatedEventArgs",
"T:LibreMetaverse.InventorySettings",
"T:LibreMetaverse.InventorySnapshot",
"T:LibreMetaverse.InventorySound",
"T:LibreMetaverse.InventoryTexture",
"T:LibreMetaverse.InventoryWearable",
"T:LibreMetaverse.Permissions",
}
def require_markers(path: Path, markers: tuple[str, ...]) -> None:
text = path.read_text()
missing = [marker for marker in markers if marker not in text]
if missing:
raise SystemExit(f"{path.name}: audit evidence missing: " + ", ".join(missing))
def main() -> None:
missing = sorted(REQUIRED_TYPES - generate_api_shims.NATIVE_TYPES.keys())
if missing:
raise SystemExit("issue 61 native types missing: " + ", ".join(missing))
if STUB_RE.search(SOURCE.read_text()):
raise SystemExit("issue 61 owned Rust stubs remain in inventory.rs")
require_markers(SOURCE, (
"MAX_CACHE_BYTES", "MAX_CACHE_RECORDS", "MAX_HIERARCHY_DEPTH",
"rebuild_indexes_and_counts", "replace_file", "would_create_cycle",
"callbacks_run_after_store_lock_is_released",
"cache_rejects_corruption_and_unknown_versions",
"cache_round_trip_preserves_roots_concrete_type_and_permissions",
"system_folders_sort_first_and_are_discoverable",
))
require_markers(DOC, ("misclassified-link", "64 MiB", "rollback", "No inventory"))
require_markers(STORE_TESTS, ("concurrent_add_move_remove_stress", "link_index_updates_on_asset_change"))
require_markers(LINK_TESTS, ("inventory_store_indexer_returns_wearable", "resolved_item_id_on_misclassified_texture_link"))
print("issue 61 audit: native models, concrete hierarchy storage, bounded cache, lock-free callbacks, and compatibility regressions are present")
if __name__ == "__main__":
main()

View File

@@ -63,6 +63,31 @@ NATIVE_TYPES = {
"T:LibreMetaverse.HttpCapsClient.ProgressReport": "crate::caps_http::HttpCapsClientProgressReport",
"T:LibreMetaverse.InstantMessage": "crate::agent_manager::InstantMessage",
"T:LibreMetaverse.InstantMessageEventArgs": "crate::agent_manager::InstantMessageEventArgs",
"T:LibreMetaverse.Inventory": "crate::inventory::Inventory",
"T:LibreMetaverse.InventoryAnimation": "crate::inventory::InventoryAnimation",
"T:LibreMetaverse.InventoryAttachment": "crate::inventory::InventoryAttachment",
"T:LibreMetaverse.InventoryBase": "crate::inventory::InventoryBase",
"T:LibreMetaverse.InventoryCallingCard": "crate::inventory::InventoryCallingCard",
"T:LibreMetaverse.InventoryCategory": "crate::inventory::InventoryCategory",
"T:LibreMetaverse.InventoryFolder": "crate::inventory::InventoryFolder",
"T:LibreMetaverse.InventoryGesture": "crate::inventory::InventoryGesture",
"T:LibreMetaverse.InventoryItem": "crate::inventory::InventoryItem",
"T:LibreMetaverse.InventoryLSL": "crate::inventory::InventoryLSL",
"T:LibreMetaverse.InventoryLandmark": "crate::inventory::InventoryLandmark",
"T:LibreMetaverse.InventoryMaterial": "crate::inventory::InventoryMaterial",
"T:LibreMetaverse.InventoryNode": "crate::inventory::InventoryNode",
"T:LibreMetaverse.InventoryNodeDictionary": "crate::inventory::InventoryNodeDictionary",
"T:LibreMetaverse.InventoryNotecard": "crate::inventory::InventoryNotecard",
"T:LibreMetaverse.InventoryObject": "crate::inventory::InventoryObject",
"T:LibreMetaverse.InventoryObjectAddedEventArgs": "crate::inventory::InventoryObjectAddedEventArgs",
"T:LibreMetaverse.InventoryObjectRemovedEventArgs": "crate::inventory::InventoryObjectRemovedEventArgs",
"T:LibreMetaverse.InventoryObjectUpdatedEventArgs": "crate::inventory::InventoryObjectUpdatedEventArgs",
"T:LibreMetaverse.InventorySettings": "crate::inventory::InventorySettings",
"T:LibreMetaverse.InventorySnapshot": "crate::inventory::InventorySnapshot",
"T:LibreMetaverse.InventorySound": "crate::inventory::InventorySound",
"T:LibreMetaverse.InventoryTexture": "crate::inventory::InventoryTexture",
"T:LibreMetaverse.InventoryWearable": "crate::inventory::InventoryWearable",
"T:LibreMetaverse.Permissions": "crate::inventory::Permissions",
"T:LibreMetaverse.ChatEventArgs": "crate::agent_messages::ChatEventArgs",
"T:LibreMetaverse.ChatSessionMember": "crate::agent_messages::ChatSessionMember",
"T:LibreMetaverse.ChatSessionMemberAddedEventArgs": "crate::agent_messages::ChatSessionMemberAddedEventArgs",
@@ -1560,6 +1585,21 @@ VALUE_DERIVES = {
"T:LibreMetaverse.Vector3d": "Clone, Copy, Debug",
"T:LibreMetaverse.WorldSettings": "Clone, Debug, Eq, PartialEq",
}
# Native implementations occasionally need Rust-only bounds that have no
# direct C# metadata equivalent. C#'s `where T : class` permits returning a
# reference to the stored object; the Rust inventory store returns an owned
# value, so its generic compatibility accessors clone the concrete item.
NATIVE_MEMBER_BOUNDS = {
"M:LibreMetaverse.Inventory.GetValueOrDefault``1(LibreMetaverse.UUID)": {
"T": "T: Clone + 'static",
},
"M:LibreMetaverse.Inventory.TryGetValue``1(LibreMetaverse.UUID,``0@)": {
"T": "T: Clone + 'static",
},
}
def generic_names(item: dict) -> list[str]:
return [parameter["name"] for parameter in item.get("generic_parameters", [])]
@@ -1649,6 +1689,11 @@ def render_compile_fixture(
*(owner_bounds.get(name, name) for name in owner_names),
*generic_declarations(member, mapper, owner_names),
]
member_bounds = NATIVE_MEMBER_BOUNDS.get(member["doc_id"], {})
parameters = [
member_bounds.get(parameter.split(":", 1)[0], parameter)
for parameter in parameters
]
if member["doc_id"] == "M:LibreMetaverse.Utils.EnumTryParse``1(System.String,``0@)":
parameters = [
*owner_names,

View File

@@ -993,6 +993,7 @@ def validate_generated_shims() -> None:
"crate::genepool_catalog::",
"crate::gesture::",
"crate::json_codec::",
"crate::inventory::",
"crate::message_codec::",
"crate::message_decoder::",
"crate::notation::",