zuzu-rust 0.2.0

Rust implementation of ZuzuScript
Documentation
from std/path/z import ZPath;
from test/more import *;

function compile  (    p    ) { return new ZPath(path: p) }
function query    ( d, p    ) { return compile(p).query(d) }
function first    ( d, p, f ) { return compile(p).first(d, f) }
function exists   ( d, p    ) { return compile(p).exists(d) }

let data := {
	users: [
		{
			name: "Ada",
			roles: [ "admin", "writer" ],
		},
		{
			name: "Bob",
			roles: [ "reader" ],
		},
	],
	meta: {
		enabled: true,
	},
};

let wildcard_parent_roundtrip := query( data, "/users/*/name/../name" );
is( wildcard_parent_roundtrip.length(), 2, "* preserves parent metadata for .. round-trip" );
is( wildcard_parent_roundtrip[0], "Ada", "* metadata parent round-trip first entry" );
is( wildcard_parent_roundtrip[1], "Bob", "* metadata parent round-trip second entry" );

let descendant_parent_roundtrip := query( data, "/**/name/../name" );
ok( descendant_parent_roundtrip.length() >= 2, "** preserves parent metadata for .. round-trip" );

let named_index_roundtrip := query( data, "/users/*/name/../../#0/name" );
is( named_index_roundtrip.length(), 1, "#n can resolve from parent metadata after named segment" );
is( named_index_roundtrip[0], "Ada", "#n round-trip first anchor resolves first user" );

let ancestors_reanchor := query( data, "/users/#1/name/..*/users/#0/name" );
is( ancestors_reanchor.length(), 1, "..* keeps ancestor chain for re-anchoring" );
is( ancestors_reanchor[0], "Ada", "..* re-anchor resolves first user" );

let key_after_parent := query( data, "/users/#1/name/../*[key() == \"roles\"]/#0" );
is( key_after_parent.length(), 1, "key metadata survives .. followed by *" );
is( key_after_parent[0], "reader", "key metadata selects roles from parent" );

function _query_throws ( String path ) {
	try {
		query( data, path );
		return false;
	}
	catch {
		return true;
	}
}

ok(
	_query_throws( "/users/*[(index() == 0)?name:\"x\"]" ),
	"ternary punctuation requires whitespace in filters"
);
is(
	query( data, "/users/*[index() == 1]/name" )[0],
	"Bob",
	"spaced binary operators remain valid"
);

done_testing();