Compare commits
16 Commits
cff6739d56
...
cbfb3f2e37
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | cbfb3f2e37 | |
Savanni D'Gerinel | 9540a2c5bb | |
Savanni D'Gerinel | 6165d65977 | |
Savanni D'Gerinel | 4f8a1636c1 | |
Savanni D'Gerinel | 20b02fbd90 | |
Savanni D'Gerinel | 278ec27b4e | |
Savanni D'Gerinel | 8b7add37c1 | |
Savanni D'Gerinel | 5441a3c441 | |
Savanni D'Gerinel | b1374229f3 | |
Savanni D'Gerinel | bc5042c004 | |
Savanni D'Gerinel | 0534143d6b | |
Savanni D'Gerinel | d7f5269e15 | |
Savanni D'Gerinel | c913e9da37 | |
Savanni D'Gerinel | c50bd652f1 | |
Savanni D'Gerinel | 093e1f7f8a | |
Savanni D'Gerinel | 3c94f906a6 |
|
@ -2503,6 +2503,16 @@ dependencies = [
|
|||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nary_tree"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb86edb8951cb3852cbb33ef558650e9f18c9d2e7fd79a6849c984a3825719c7"
|
||||
dependencies = [
|
||||
"slab",
|
||||
"snowflake",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.11"
|
||||
|
@ -2705,6 +2715,7 @@ dependencies = [
|
|||
"config-derive",
|
||||
"cool_asserts",
|
||||
"grid",
|
||||
"nary_tree",
|
||||
"serde 1.0.193",
|
||||
"serde_json",
|
||||
"sgf",
|
||||
|
@ -3685,6 +3696,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"cool_asserts",
|
||||
"nary_tree",
|
||||
"nom",
|
||||
"serde 1.0.193",
|
||||
"thiserror",
|
||||
|
@ -3766,6 +3778,12 @@ version = "1.11.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "snowflake"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.10"
|
||||
|
|
55
Cargo.nix
55
Cargo.nix
|
@ -7917,6 +7917,28 @@ rec {
|
|||
};
|
||||
resolvedDefaultFeatures = [ "default" ];
|
||||
};
|
||||
"nary_tree" = rec {
|
||||
crateName = "nary_tree";
|
||||
version = "0.4.3";
|
||||
edition = "2021";
|
||||
sha256 = "1iqray1a716995l9mmvz5sfqrwg9a235bvrkpcn8bcqwjnwfv1pv";
|
||||
authors = [
|
||||
"Ian <iwburns8@gmail.com>"
|
||||
"David Cohen <dacohen@pm.me>"
|
||||
];
|
||||
dependencies = [
|
||||
{
|
||||
name = "slab";
|
||||
packageId = "slab";
|
||||
}
|
||||
{
|
||||
name = "snowflake";
|
||||
packageId = "snowflake";
|
||||
}
|
||||
];
|
||||
features = {
|
||||
};
|
||||
};
|
||||
"native-tls" = rec {
|
||||
crateName = "native-tls";
|
||||
version = "0.2.11";
|
||||
|
@ -8551,6 +8573,10 @@ rec {
|
|||
name = "grid";
|
||||
packageId = "grid";
|
||||
}
|
||||
{
|
||||
name = "nary_tree";
|
||||
packageId = "nary_tree";
|
||||
}
|
||||
{
|
||||
name = "serde";
|
||||
packageId = "serde 1.0.193";
|
||||
|
@ -8568,6 +8594,11 @@ rec {
|
|||
name = "thiserror";
|
||||
packageId = "thiserror";
|
||||
}
|
||||
{
|
||||
name = "uuid";
|
||||
packageId = "uuid 0.8.2";
|
||||
features = [ "v4" "serde" ];
|
||||
}
|
||||
];
|
||||
devDependencies = [
|
||||
{
|
||||
|
@ -8647,6 +8678,11 @@ rec {
|
|||
packageId = "tokio";
|
||||
features = [ "full" ];
|
||||
}
|
||||
{
|
||||
name = "uuid";
|
||||
packageId = "uuid 0.8.2";
|
||||
features = [ "v4" "serde" ];
|
||||
}
|
||||
];
|
||||
buildDependencies = [
|
||||
{
|
||||
|
@ -11560,6 +11596,10 @@ rec {
|
|||
packageId = "chrono";
|
||||
features = [ "serde" ];
|
||||
}
|
||||
{
|
||||
name = "nary_tree";
|
||||
packageId = "nary_tree";
|
||||
}
|
||||
{
|
||||
name = "nom";
|
||||
packageId = "nom";
|
||||
|
@ -11793,6 +11833,21 @@ rec {
|
|||
};
|
||||
resolvedDefaultFeatures = [ "const_generics" "const_new" "union" ];
|
||||
};
|
||||
"snowflake" = rec {
|
||||
crateName = "snowflake";
|
||||
version = "1.3.0";
|
||||
edition = "2015";
|
||||
sha256 = "1wadr7bxdxbmkbqkqsvzan6q1h3mxqpxningi3ss3v9jaav7n817";
|
||||
authors = [
|
||||
"Steven Allen <steven@stebalien.com>"
|
||||
];
|
||||
features = {
|
||||
"serde" = [ "dep:serde" ];
|
||||
"serde_derive" = [ "dep:serde_derive" ];
|
||||
"serde_support" = [ "serde" "serde_derive" ];
|
||||
};
|
||||
resolvedDefaultFeatures = [ "default" ];
|
||||
};
|
||||
"socket2 0.4.10" = rec {
|
||||
crateName = "socket2";
|
||||
version = "0.4.10";
|
||||
|
|
|
@ -0,0 +1,474 @@
|
|||
{
|
||||
"registry+https://github.com/rust-lang/crates.io-index#addr2line@0.21.0": "1jx0k3iwyqr8klqbzk6kjvr496yd94aspis10vwsj5wy7gib4c4a",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#adler32@1.2.0": "0d7jq7jsjyhsgbhnfq5fvrlh9j0i9g1fqrl2735ibv5f75yjgqda",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#adler@1.0.2": "1zim79cvzd5yrkzl3nyfx0avijwgk9fqv3yrscdy1cc79ih02qpj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#ahash@0.8.6": "0yn9i8nc6mmv28ig9w3dga571q09vg9f1f650mi5z8phx42r6hli",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.2": "1w510wnixvlgimkx1zjbvlxh6xps2vjgfqgwf5a6adlbjp5rv5mj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#allocator-api2@0.2.16": "1iayppgq4wqbfbfcqmsbwgamj0s65012sskfvyx07pxavk3gyhh9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#android-tzdata@0.1.1": "1w7ynjxrfs97xg3qlcdns4kgfpwcdv824g611fq32cag4cdr96g9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#android_system_properties@0.1.5": "04b3wrz12837j7mdczqd95b732gw5q7q66cv4yn4646lvccp57l1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#anstream@0.6.5": "1dm1mdbs1x6y3m3pz0qlamgiskb50i4q859676kx0pz8r8pajr6n",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#anstyle-parse@0.2.3": "134jhzrz89labrdwxxnjxqjdg06qvaflj1wkfnmyapwyldfwcnn7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#anstyle-query@1.0.2": "0j3na4b1nma39g4x7cwvj009awxckjf3z2vkwhldgka44hqj72g2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#anstyle-wincon@3.0.2": "19v0fv400bmp4niqpzxnhg83vz12mmqv7l2l8vi80qcdxj0lpm8w",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#anstyle@1.0.4": "11yxw02b6parn29s757z96rgiqbn8qy0fk9a3p3bhczm85dhfybh",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.75": "1rmcjkim91c5mw7h9wn8nv0k6x118yz0xg0z1q18svgn42mqqrm4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-channel@1.9.0": "0dbdlkzlncbibd3ij6y6jmvjd0cmdn48ydcfdpfhw09njd93r5c1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-channel@2.1.1": "1337ywc1paw03rdlwh100kh8pa0zyp0nrlya8bpsn6zdqi5kz8qw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-executor@1.8.0": "0z7rpayidhdqs4sdzjhh26z5155c1n94fycqni9793n4zjz5xbhp",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-global-executor@2.4.1": "1762s45cc134d38rrv0hyp41hv4iv6nmx59vswid2p0il8rvdc85",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-io@1.13.0": "1byj7lpw0ahk6k63sbc9859v68f28hpaab41dxsjj1ggjdfv9i8g",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-io@2.3.1": "0rggn074kbqxxajci1aq14b17gp75rw9l6rpbazcv9q0bc6ap5wg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-lock@2.8.0": "0asq5xdzgp3d5m82y5rg7a0k9q0g95jy6mgc7ivl334x7qlp4wi8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-lock@3.3.0": "0yxflkfw46rad4lv86f59b5z555dlfmg1riz1n8830rgi0qb8d6h",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-std@1.12.0": "0pbgxhyb97h4n0451r26njvr20ywqsbm6y1wjllnp4if82s5nmk2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-task@4.7.0": "16975vx6aqy5yf16fs9xz5vx1zq8mwkzfmykvcilc1j7b6c6xczv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.77": "1adf1jh2yg39rkpmqjqyr9xyd6849p0d95425i6imgbhx0syx069",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#atoi@2.0.0": "0a05h42fggmy7h0ajjv6m7z72l924i7igbx13hk9d8pyign9k3gj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#atomic-waker@1.1.2": "1h5av1lw56m0jf0fd3bchxq8a30xv0b4wv8s4zkp4s0i7mfvs18m",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#atomic-write-file@0.1.2": "0dl4x0srdwjxm3zz3fj1c7m44i3b7mjiad550fqklj1n4bfbxkgd",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#autocfg@0.1.8": "0y4vw4l4izdxq1v0rrhvmlbqvalrqrmk60v1z0dqlgnlbzkl7phd",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#autocfg@1.1.0": "1ylp3cb47ylzabimazvbz9ms6ap784zhb6syaz6c1jqpmcmq0s6l",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#backtrace@0.3.69": "0dsq23dhw4pfndkx2nsa1ml2g31idm7ss7ljxp8d57avygivg290",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#base64@0.21.5": "1y8x2xs9nszj5ix7gg4ycn5a6wy7ca74zxwqri3bdqzdjha6lqrm",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#base64@0.9.3": "0hs62r35bgxslawyrn1vp9rmvrkkm76fqv0vqcwd048vs876r7a8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#base64ct@1.6.0": "0nvdba4jb8aikv60az40x2w1y96sjdq8z3yp09rwzmkhiwv1lg4c",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bit-set@0.5.3": "1wcm9vxi00ma4rcxkl3pzzjli6ihrpn9cfdi0c5b4cvga2mxs007",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bit-vec@0.6.3": "1ywqjnv60cdh1slhz67psnp422md6jdliji6alq0gmly2xm9p7rl",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bit_field@0.10.2": "0qav5rpm4hqc33vmf4vc4r0mh51yjx5vmd9zhih26n9yjs3730nw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bitflags@1.3.2": "12ki6w8gn1ldq7yz9y680llwk5gmrhrzszaa17g1sbrw2r2qvwxy",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bitflags@2.4.1": "01ryy3kd671b0ll4bhdvhsz67vwz1lz53fz504injrd7wpv64xrj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#block-buffer@0.10.4": "0w9sa2ypmrsqqvc20nhwr75wbb5cjr4kkyhpjm1z1lv2kdicfy1h",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#blocking@1.5.1": "064i3d6b8ln34fgdw49nmx9m36bwi3r3nv8c9xhcrpf4ilz92dva",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#build_html@2.4.0": "188nibbsv33vgjjiq9cn2irsgdb75gxfipavcavnyydcwxpzw21i",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bumpalo@3.14.0": "1v4arnv9kwk54v5d0qqpv4vyw2sgr660nk0w3apzixi1cm3yfc3z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bytemuck@1.14.0": "1ik1ma5n3bg700skkzhx50zjk7kj7mbsphi773if17l04pn2hk9p",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#byteorder@1.5.0": "0jzncxyf404mwqdbspihyzpkndfgda450l0893pz5xj685cg5l0z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#bytes@1.5.0": "08w2i8ac912l8vlvkv3q51cd4gr09pwlg3sjsjffcizlrb0i5gd2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cairo-rs@0.18.3": "18d80lk853bjhx36rjaj78clzfjrmlgi01863drnmshdgxi16dpk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cairo-sys-rs@0.18.2": "0lfsxl7ylw3phbnwmz3k58j1gnqi6kc2hdc7g3bb7f4hwnl9yp38",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cc@1.0.83": "1l643zidlb5iy1dskc5ggqs4wqa29a02f44piczqc8zcnsq4y5zi",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cfg-expr@0.15.5": "1cqicd9qi8mzzgh63dw03zhbdihqfl3lbiklrkynyzkq67s5m483",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.0": "1za0vb97n4brpzpv8lsbnzmq5r8f2b0cpqqr0sy8h5bn751xxwds",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#chrono-tz-build@0.2.1": "03rmzd69cn7fp0fgkjr5042b3g54s2l941afjm3001ls7kqkjgj3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#chrono-tz@0.8.4": "0xhd3dsfs72im0sbc7w889lfy7bxgjlbvqhj5a1yvxhxwb08acg2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.31": "0f6vg67pipm8cziad2yms6a639pssnvysk1m05dd9crymmdnhb3z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#clap@4.4.11": "1wj5gb2fnqls00zfahg3490bdfc36d9cwpl80qjacb5jyrqzdbxz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#clap_builder@4.4.11": "1fxdsmw1ilgswz3lg2hjlvsdyyz04k78scjirlbd7c9bc83ba5m2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#clap_derive@4.4.7": "0hk4hcxl56qwqsf4hmf7c0gr19r9fbxk0ah2bgkr36pmmaph966g",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#clap_lex@0.6.0": "1l8bragdvim7mva9flvd159dskn2bdkpl0jqrr41wnjfn8pcfbvh",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cloudabi@0.0.3": "0kxcg83jlihy0phnd2g8c2c303px3l2p3pkjz357ll6llnd5pz6x",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#color_quant@1.1.0": "12q1n427h2bbmmm1mnglr57jaz2dj9apk0plcxw7nwqiai7qjyrx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#colorchoice@1.0.0": "1ix7w85kwvyybwi2jdkl3yva2r2bvdcc3ka2grjfzfgrapqimgxc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#concurrent-queue@2.4.0": "0qvk23ynj311adb4z7v89wk3bs65blps4n24q8rgl23vjk6lhq6i",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#const-oid@0.9.6": "1y0jnqaq7p2wvspnx7qj76m7hjcqpz73qzvr9l2p9n2s51vr6if2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cookie@0.17.0": "096c52jg9iq4lfcps2psncswv33fc30mmnaa2sbzzcfcw71kgyvy",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cool_asserts@2.0.3": "1v18dg7ifx41k2f82j3gsnpm1fg9wk5s4zv7sf42c7pnad72b7zf",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#core-foundation-sys@0.8.6": "13w6sdf06r0hn7bx2b45zxsg1mm2phz34jikm6xc5qrbr6djpsh6",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#core-foundation@0.9.4": "13zvbbj07yk3b61b8fhwfzhy35535a583irf23vlcg59j7h9bqci",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#cpufeatures@0.2.11": "1l0gzsyy576n017g9bf0vkv5hhg9cpz1h1libxyfdlzcgbh0yhnf",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crc-catalog@2.4.0": "1xg7sz82w3nxp1jfn425fvn1clvbzb3zgblmxsyqpys0dckp9lqr",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crc32fast@1.3.2": "03c8f29yx293yf43xar946xbls1g60c207m9drf8ilqhr25vsh5m",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crc@3.0.1": "1zkx87a5x06xfd6xm5956w4vmdfs0wcxpsn7iwj5jbp2rcapmv46",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crossbeam-deque@0.8.4": "0la7fx9n1vbx3h23va0xmcy36hziql1pkik08s3j3asv4479ma7w",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crossbeam-epoch@0.9.16": "1anr32r8px0vb65cgwbwp3zhqz69scz5dgq9bmx54w5qa59yjbrd",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crossbeam-queue@0.3.9": "0lz17pgydh29w8brld8dysi1m4n5bxfpnj8w9bxk0q6xpyyzbg5r",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.17": "13y7wh993i7q71kg6wcfj65w3rlmizzrz7cqgz1l9whlgw9rcvf0",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crunchy@0.2.2": "1dx9mypwd5mpfbbajm78xcrg5lirqk7934ik980mmaffg3hdm0bs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#crypto-common@0.1.6": "1cvby95a6xg7kxdz5ln3rl9xh66nz66w46mm3g56ri1z5x815yqv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#data-encoding@2.5.0": "1rcbnwfmfxhlshzbn3r7srm3azqha3mn33yxyqxkzz2wpqcjm5ky",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#deflate@0.8.6": "0x6iqlayg129w63999kz97m279m0jj4x4sm6gkqlvmp73y70yxvk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#der@0.7.8": "070bwiyr80800h31c5zd96ckkgagfjgnrrdmz3dzg2lccsd3dypz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#deranged@0.3.10": "1p4i64nkadamksa943d6gk39sl1kximz0xr69n408fvsl1q0vcwf",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#digest@0.10.7": "14p2n6ih29x81akj097lvz7wi9b6b9hvls0lwrv7b6xwyy0s5ncy",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#dimensioned@0.7.0": "09ky8s3higkf677lmyqg30hmj66gpg7hx907s6hfvbk2a9av05r5",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#dimensioned@0.8.0": "15s3j4ry943xqlac63bp81sgdk9s3yilysabzww35j9ibmnaic50",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.4": "0p8pyg10csc782qlwx3znr6qx46ni96m1qh597kmyrf6s3s8axa8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#dotenvy@0.15.7": "16s3n973n5aqym02692i1npb079n5mb0fwql42ikmwn8wnrrbbqs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#either@1.9.0": "01qy3anr7jal5lpc20791vxrw0nl6vksb5j7x56q2fycgcyy8sm2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#encoding_rs@0.8.33": "1qa5k4a0ipdrxq4xg9amms9r9pnnfn7nfh2i9m3mw0ka563b6s3j",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#env_logger@0.10.1": "1kmy9xmfjaqfvd4wkxr1f7d16ld3h9b487vqs2q9r0s8f3kg7cwm",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#equivalent@1.0.1": "1malmx5f4lkfvqasz319lq6gb3ddg19yzf9s8cykfsgzdmyq0hsl",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#errno@0.3.8": "0ia28ylfsp36i27g1qih875cyyy4by2grf80ki8vhgh6vinf8n52",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#etcetera@0.8.0": "0hxrsn75dirbjhwgkdkh0pnpqrnq17ypyhjpjaypgax1hd91nv8k",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#event-listener-strategy@0.4.0": "1lwprdjqp2ibbxhgm9khw7s7y7k4xiqj5i5yprqiks6mnrq4v3lm",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#event-listener@2.5.3": "1q4w3pndc518crld6zsqvvpy9lkzwahp2zgza9kbzmmqh9gif1h2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#event-listener@4.0.1": "04k7qbi5kgs36s905gxijj41kcr78xs2s6cp6vbg50254z7wvwl4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#exr@1.71.0": "1a58k179b0h8zpf1cfgc2vl60j2syg7cdgdzp9j6cgmb6lgpcal3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fastrand@1.9.0": "1gh12m56265ihdbzh46bhh0jf74i197wm51jg1cw75q7ggi96475",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fastrand@2.0.1": "19flpv5zbzpf0rk4x77z4zf25in0brg8l7m304d3yrf47qvwxjr5",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fdeflate@0.3.1": "0s5885wdsih2hqx3hsl7l8cl3666fgsgiwvglifzy229hpydmmk4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#field-offset@0.3.6": "0zq5sssaa2ckmcmxxbly8qgz3sxpb8g1lwv90sdh1z74qif2gqiq",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#finl_unicode@1.2.0": "1ipdx778849czik798sjbgk5yhwxqybydac18d2g9jb20dxdrkwg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#flate2@1.0.28": "03llhsh4gqdirnfxxb9g2w9n0721dyn4yjir3pz7z4vjaxb3yc26",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fluent-bundle@0.15.2": "1zbzm13rfz7fay7bps7jd4j1pdnlxmdzzfymyq2iawf9vq0wchp2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fluent-langneg@0.13.0": "152yxplc11vmxkslvmaqak9x86xnavnhdqyhrh38ym37jscd0jic",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fluent-syntax@0.11.0": "0y6ac7z7sbv51nsa6km5z8rkjj4nvqk91vlghq1ck5c3cjbyvay0",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fluent@0.16.0": "19s7z0gw95qdsp9hhc00xcy11nwhnx93kknjmdvdnna435w97xk1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#flume@0.11.0": "10girdbqn77wi802pdh55lwbmymy437k7kklnvj12aaiwaflbb2m",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fnv@1.0.7": "1hc2mcqha06aibcaza94vbi81j6pr9a1bbxrxjfhc91zin8yr7iz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1": "0jxgzd04ra4imjv8jgkmdq59kj8fsz6w4zxsbmlai34h26225c00",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2": "1cgk0vyd7r45cj769jym4a6s7vwshvd0z4bqrb92q1fwibmkkwzn",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.1": "0milh8x7nl4f450s3ddhg57a3flcv6yq8hlkyk6fyr3mcb128dp1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#fuchsia-cprng@0.1.1": "1fnkqrbz7ixxzsb04bsz9p0zzazanma8znfdqjvh39n14vapfvx0",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-channel@0.3.29": "1jxsifvrbqzdadk0svbax71cba5d3qg3wgjq8i160mxmd1kdckgz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.29": "1308bpj0g36nhx2y6bl4mm6f1gnh9xyvvw2q2wpdgnb6dv3247gb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-executor@0.3.29": "1g4pjni0sw28djx6mlcfz584abm2lpifz86cmng0kkxh7mlvhkqg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-intrusive@0.5.0": "0vwm08d1pli6bdaj0i7xhk3476qlx4pll6i0w03gzdnh7lh0r4qx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-io@0.3.29": "1ajsljgny3zfxwahba9byjzclrgvm1ypakca8z854k2w7cb4mwwb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-lite@1.13.0": "1kkbqhaib68nzmys2dc8j9fl2bwzf2s91jfk13lb2q3nwhfdbaa9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-lite@2.2.0": "1flj85i6xm0rjicxixmajrp6rhq8i4bnbzffmrd6h23ln8jshns4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-macro@0.3.29": "1nwd18i8kvpkdfwm045hddjli0n96zi7pn6f99zi9c74j7ym7cak",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.29": "05q8jykqddxzp8nwf00wjk5m5mqi546d7i8hsxma7hiqxrw36vg3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-task@0.3.29": "1qmsss8rb5ppql4qvd4r70h9gpfcpd0bg2b3qilxrnhdkc397lgg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.29": "0141rkqh0psj4h8x8lgsl1p29dhqr7z2wcixkcbs60z74kb2d5d1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#futures@0.3.29": "0dak2ilpcmyjrb1j54fzy9hlw6vd10vqljq9gd59pbrq9dqr00ns",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gdk-pixbuf-sys@0.18.0": "1xya543c4ffd2n7aiwwrdxsyc9casdbasafi6ixcknafckm3k61z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gdk-pixbuf@0.18.3": "0b68ssdyapvq3bgsna9frabbzhjkvvzz8jld4mxkphr29nvk4vs4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gdk4-sys@0.7.2": "1w7yvir565sjrrw828lss07749hfpfsr19jdjzwivkx36brl7ayv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gdk4@0.7.3": "1xiacc63p73apr033gjrb9dsk0y4yxnsljwfxbwfry41snd03nvy",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#generic-array@0.11.2": "0a7w8w0rg47nmcinnfzv443lcyb8mplwc251p1jyr5xj2yh6wzv6",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#generic-array@0.14.7": "16lyyrzrljfq424c3n8kfwkqihlimmsg5nhshbbp48np3yjrqr45",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#getrandom@0.2.11": "03q7120cc2kn7ry013i67zmjl2g9q73h1ks5z08hq5v9syz0d47y",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gif@0.11.4": "01hbw3isapzpzff8l6aw55jnaqx2bcscrbwyf3rglkbbfp397p9y",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gif@0.12.0": "0ibhjyrslfv9qm400gp4hd50v9ibva01j4ab9bwiq1aycy9jayc0",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gimli@0.28.1": "0lv23wc8rxvmjia3mcxc6hj9vkqnv1bqq0h8nzjcgf71mrxx6wa2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gio-sys@0.18.1": "1lip8z35iy9d184x2qwjxlbxi64q9cpayy7v1p5y9xdsa3w6smip",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gio@0.18.4": "0wsc6mnx057s4ailacg99dwgna38dbqli5x7a6y9rdw75x9qzz6l",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#glib-build-tools@0.16.3": "1z73bl10zmxwrv16v4f5wcky1f3z5a2v0hknca54al4k2p5ka695",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#glib-build-tools@0.17.10": "05p7ab2vn8962cbchi7a6hndhvw64nqk4w5kpg5z53iizsgdfrbs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#glib-build-tools@0.18.0": "0p5c2ayiam5bkp9wvq9f9ihwp06nqs5j801npjlwnhrl8rpwac9l",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#glib-macros@0.18.3": "19crnw5a57w02njpbsmdqwbkncl6hw6g3mv554y8dqzcrri3jybj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#glib-sys@0.18.1": "164qhsfmlzd5mhyxs8123jzbdfldwxbikfpq5cysj3lddbmy4g06",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#glib@0.18.4": "0kjws6ns6dym48nzxz9skhipk55flc2hy5q5kzg4w12wvizvs6wm",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gloo-timers@0.2.6": "0p2yqcxw0q9kclhwpgshq1r4ijns07nmmagll3lvrgl7pdk5m6cv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gobject-sys@0.18.0": "0i6fhp3m6vs3wkzyc22rk2cqj68qvgddxmpaai34l72da5xi4l08",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#graphene-rs@0.18.1": "00f4q1ra4haap5i7lazwhkdgnb49fs8adk2nm6ki6mjhl76jh8iv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#graphene-sys@0.18.1": "0n8zlg7z26lwpnvlqp1hjlgrs671skqwagdpm7r8i1zwx3748hfc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#grid@0.9.0": "0iswdcxggyxp9m1rz0m7bfg4xacinvn78zp2fgfp0l0079x10d06",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gsk4-sys@0.7.3": "0mbdlm9qi1hql48rr29vsj9vlqwc7gxg67wg1q19z67azwz9xg8j",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gsk4@0.7.3": "0zhzs2dkgiinhgc11akpn2harq3x5n1iq21dnc4h689g3lsqx58d",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gtk4-macros@0.7.2": "0bw3cchiycf7dw1bw4p8946gv38azxy05a5w0ndgcmxnz6fc8znm",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gtk4-sys@0.7.3": "1f2ylskyqkjdik9fij2m46pra4jagnif5xyalbxfk3334fmc9n2l",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#gtk4@0.7.3": "0hh8nzglmz94v1m1h6vy8z12m6fr7ia467ry0md5fa4p7sm53sss",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#h2@0.3.22": "0y41jlflvw8niifdirgng67zdmic62cjf5m2z69hzrpn5qr50qjd",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#half@2.2.1": "1l1gdlzxgm7wc8xl5fxas20kfi1j35iyb7vfjkghbdzijcvazd02",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.14.3": "012nywlg0lj9kwanh69my5x67vjlfmzfi9a0rq4qvis2j8fil3r9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hashlink@0.8.4": "1xy8agkyp0llbqk9fcffc1xblayrrywlyrm2a7v93x8zygm4y2g8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#headers-core@0.2.0": "0ab469xfpd411mc3dhmjhmzrhqikzyj8a17jn5bkj9zfpy0n9xp7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#headers@0.3.9": "0w62gnwh2p1lml0zqdkrx9dp438881nhz32zrzdy61qa0a9kns06",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#heck@0.4.1": "1a7mqsnycv5z4z5vnv1k34548jzmc0ajic7c1j8jsaspnhw5ql4m",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hermit-abi@0.3.3": "1dyc8qsjh876n74a3rcz8h43s27nj1sypdhsn2ms61bd3b47wzyp",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hex-string@0.1.0": "02sgrgrbp693jv0v5iga7z47y6aj93cq0ia39finby9x17fw53l4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hex@0.4.3": "0w1a4davm1lgzpamwnba907aysmlrnygbqmfis2mqjx5m552a93z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hkdf@0.12.4": "1xxxzcarz151p1b858yn5skmhyrvn8fs4ivx5km3i1kjmnr8wpvv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hmac@0.12.1": "0pmbr069sfg76z7wsssfk5ddcqd9ncp79fyz6zcm6yn115yc6jbc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#home@0.5.9": "19grxyg35rqfd802pcc9ys1q3lafzlcjcv2pl2s5q8xpyr5kblg3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#http-body@0.4.6": "1lmyjfk6bqk6k9gkn1dxq770sb78pqbqshga241hr5p995bb5skw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#http@0.2.11": "1fwz3mhh86h5kfnr5767jlx9agpdggclq7xsqx930fflzakb2iw9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#http@1.0.0": "1sllw565jn8r5w7h928nsfqq33x586pyasdfr7vid01scwwgsamk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#httparse@1.8.0": "010rrfahm1jss3p022fqf3j3jmm72vhn4iqhykahb9ynpaag75yq",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#httpdate@1.0.3": "1aa9rd2sac0zhjqh24c9xvir96g188zldkx0hr6dnnlx5904cfyz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#humantime@2.1.0": "1r55pfkkf5v0ji1x6izrjwdq9v6sc7bv99xj6srywcar37xmnfls",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hyper-tls@0.5.0": "01crgy13102iagakf6q4mb75dprzr7ps1gj0l5hxm1cvm7gks66n",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hyper@0.10.16": "0wwjh9p3mzvg3fss2lqz5r7ddcgl1fh9w6my2j69d6k0lbcm41ha",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#hyper@0.14.28": "107gkvqx4h9bl17d602zkm2dgpfq86l2dr36yzfsi8l3xcsy35mz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#iana-time-zone-haiku@0.1.2": "17r6jmj31chn7xs9698r122mapq85mfnv98bb4pg6spm0si2f67k",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#iana-time-zone@0.1.58": "081vcr8z8ddhl5r1ywif6grnswk01b2ac4nks2bhn8zzdimvh9l3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#idna@0.1.5": "0kl4gs5kaydn4v07c6ka33spm9qdh2np0x7iw7g5zd8z1c7rxw1q",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#idna@0.5.0": "1xhjrcjqq0l5bpzvdgylvpkgk94panxgsirzhjnnqfdgc4a9nkb3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#image@0.23.14": "18gn2f7xp30pf9aqka877knlq308khxqiwjvsccvzaa4f9zcpzr4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#image@0.24.7": "04d7f25b8nlszfv9a474n4a0al4m2sv9gqj3yiphhqr0syyzsgbg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#indent_write@2.2.0": "1hqjp80argdskrhd66g9sh542yxy8qi77j6rc69qd0l7l52rdzhc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#indexmap@2.1.0": "07rxrqmryr1xfnmhrjlz8ic6jw28v6h5cig3ws2c9d0wifhy2c6m",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#instant@0.1.12": "0b2bx5qdlwayriidhrag8vhy10kdfimfhmb3jnjmsz2h9j1bwnvs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#intl-memoizer@0.5.1": "0vx6cji8ifw77zrgipwmvy1i3v43dcm58hwjxpb1h29i98z46463",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#intl_pluralrules@7.0.2": "0wprd3h6h8nfj62d8xk71h178q7zfn3srxm787w4sawsqavsg3h7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#io-lifetimes@1.0.11": "1hph5lz4wd3drnn6saakwxr497liznpfnv70via6s0v8x6pbkrza",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#ipnet@2.9.0": "1hzrcysgwf0knf83ahb3535hrkw63mil88iqc6kjaryfblrqylcg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#iron@0.6.1": "1s4mf8395f693nhwsr0znw3j5frzn56gzllypyl50il85p50ily6",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#is-terminal@0.4.9": "12xgvc7nsrp3pn8hcxajfhbli2l5wnh3679y2fmky88nhj4qj26b",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#itertools@0.12.0": "1c07gzdlc6a1c8p8jrvvw3gs52bss3y58cs2s21d9i978l36pnr5",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.10": "0k7xjfki7mnv6yzjrbnbnjllg86acmbnk4izz2jmm1hx2wd6v95i",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#jpeg-decoder@0.1.22": "1wnh0bmmswpgwhgmlizz545x8334nlbmkq8imy9k224ri3am7792",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#jpeg-decoder@0.3.0": "0gkv0zx95i4fr40fj1a10d70lqi6lfyia8r5q8qjxj8j4pj0005w",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#js-sys@0.3.66": "1ji9la5ydg0vy17q54i7dnwc0wwb9zkx662w1583pblylm6wdsff",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#kv-log-macro@1.0.7": "0zwp4bxkkp87rl7xy2dain77z977rvcry1gmr5bssdbn541v7s0d",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#language-tags@0.2.2": "16hrjdpa827carq5x4b8zhas24d8kg4s16m6nmmn1kb7cr5qh7d9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.4.0": "0in6ikhw8mgl33wjv6q6xfrb5b9jr16q8ygjy803fay4zcisvaz2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#lebe@0.5.2": "1j2l6chx19qpa5gqcw434j83gyskq3g2cnffrbl3842ymlmpq203",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#libadwaita-sys@0.5.3": "16n6xsy6jhbj0jbpz8yvql6c9b89a99v9vhdz5s37mg1inisl42y",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#libadwaita@0.5.3": "174pzn9dwsk8ikvrhx13vkh0zrpvb3rhg9yd2q5d2zjh0q6fgrrg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#libc@0.2.151": "1x28f0zgp4zcwr891p8n9ag9w371sbib30vp4y6hi2052frplb9h",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#libm@0.2.8": "0n4hk1rs8pzw8hdfmwn96c4568s93kfxqgcqswr7sajd2diaihjf",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#libsqlite3-sys@0.27.0": "05pp60ncrmyjlxxjj187808jkvpxm06w5lvvdwwvxd2qrmnj4kng",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#linux-raw-sys@0.3.8": "068mbigb3frrxvbi5g61lx25kksy98f2qgkvc4xg8zxznwp98lzg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#linux-raw-sys@0.4.12": "0mhlla3gk1jgn6mrq9s255rvvq8a1w3yk2vpjiwsd6hmmy1imkf4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#lock_api@0.4.11": "0iggx0h4jx63xm35861106af3jkxq06fpqhpkhgw0axi2n38y5iw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#log@0.3.9": "0jq23hhn5h35k7pa8r7wqnsywji6x3wn1q5q7lif5q536if8v7p1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#log@0.4.20": "13rf7wphnwd61vazpxr7fiycin6cb1g8fmvgqg18i464p0y1drmm",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#logger@0.4.0": "14xlxvkspcfnspjil0xi63qj5cybxn1hjmr5gq8m4v1g9k5p54bc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#matches@0.1.10": "1994402fq4viys7pjhzisj4wcw894l53g798kkm2y74laxk0jci5",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#md-5@0.10.6": "1kvq5rnpm4fzwmyv5nmnxygdhhb2369888a06gdc9pxyrzh7x7nq",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#memchr@2.6.4": "0rq1ka8790ns41j147npvxcqcl2anxyngsdimy85ag2api0fwrgn",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#memoffset@0.9.0": "0v20ihhdzkfw1jx00a7zjpk2dcp5qjq6lz302nyqamd9c4f4nqss",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#mime@0.2.6": "1q1s1ax1gaz8ld3513nvhidfwnik5asbs1ma3hp6inp5dn56nqms",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17": "16hkibgvb9klh0w0jk5crr5xv90l3wlf77ggymzjmvl1818vnxv8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#mime_guess@1.8.8": "18qcd5aa3363mb742y7lf39j7ha88pkzbv9ff2qidlsdxsjjjs91",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#mime_guess@2.0.4": "1vs28rxnbfwil6f48hh58lfcx90klcvg68gxdc60spwa4cy2d4j1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#minimal-lexical@0.2.1": "16ppc5g84aijpri4jzv14rvcnslvlpphbszc7zzp6vfkddf4qdb8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#miniz_oxide@0.3.7": "0dblrhgbm0wa8jjl8cjp81akaj36yna92df4z1h9b26n3spal7br",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#miniz_oxide@0.4.4": "0jsfv00hl5rmx1nijn59sr9jmjd4rjnjhh4kdjy8d187iklih9d9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#miniz_oxide@0.7.1": "1ivl3rbbdm53bzscrd01g60l46lz5krl270487d8lhjvwl5hx0g7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#mio@0.8.10": "02gyaxvaia9zzi4drrw59k9s0j6pa5d1y2kv7iplwjipdqlhngcg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#modifier@0.1.0": "0n3fmgli1nsskl0whrfzm1gk0rmwwl6pw1q4nb9sqqmn5h8wkxa1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#multer@2.1.0": "1hjiphaypj3phqaj5igrzcia9xfmf4rr4ddigbh8zzb96k1bvb01",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#nary_tree@0.4.3": "1iqray1a716995l9mmvz5sfqrwg9a235bvrkpcn8bcqwjnwfv1pv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#native-tls@0.2.11": "0bmrlg0fmzxaycjpkgkchi93av07v2yf9k33gc12ca9gqdrn28h7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#nix@0.27.1": "0ly0kkmij5f0sqz35lx9czlbk6zpihb7yh1bsy4irzwfd2f4xc1f",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#no-std-compat@0.4.1": "132vrf710zsdp40yp1z3kgc2ss8pi0z4gmihsz3y7hl4dpd56f5r",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#nom@7.1.3": "0jha9901wxam390jcf5pfa0qqfrgh8li787jx2ip0yk5b8y9hwyj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#num-bigint-dig@0.8.4": "0lb12df24wgxxbspz4gw1sf1kdqwvpdcpwq4fdlwg4gj41c1k16w",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.45": "1ncwavvwdmsqzxnn65phv6c6nn72pnv9xhpmjd6a429mzf4k6p92",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#num-iter@0.1.43": "0lp22isvzmmnidbq9n5kbdh8gj0zm3yhxv1ddsn5rp65530fc0vx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#num-rational@0.3.2": "01sgiwny9iflyxh2xz02sak71v2isc3x608hfdpwwzxi3j5l5b0j",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#num-rational@0.4.1": "1c0rb8x4avxy3jvvzv764yk7afipzxncfnqlb10r3h53s34s2f06",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.17": "0z16bi5zwgfysz6765v3rd6whfbjpihx3mhsn4dg8dzj2c221qrr",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#num_cpus@1.16.0": "0hra6ihpnh06dvfvz9ipscys0xfqa9ca9hzp384d5m02ssvgqqa1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#object@0.32.1": "1c02x4kvqpnl3wn7gz9idm4jrbirbycyqjgiw6lm1g9k77fzkxcw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#once_cell@1.19.0": "14kvw7px5z96dk4dwdm1r9cqhhy2cyj1l5n5b29mynbb8yr15nrz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1": "173xxvfc63rr5ybwqwylsir0vq6xsj4kxiv4hmg4c3vscdmncj59",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#openssl-probe@0.1.5": "1kq18qm48rvkwgcggfkqq6pm948190czqc94d6bm2sir5hq1l0gz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.97": "02s670ir38fsavphdna07144y41dkvrcfkwnjzg82zfrrlsavsn3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.61": "0idv3n9n9f2sxq8cqzxvq44633vg5sx4n9q1p3g6dn66ikf1k13b",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pango-sys@0.18.0": "1iaxalcaaj59cl9n10svh4g50v8jrc1a36kd7n9yahx8j7ikfrs3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pango@0.18.3": "1r5ygq7036sv7w32kp8yxr6vgggd54iaavh3yckanmq4xg0px8kw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#parking@2.2.0": "1blwbkq6im1hfxp5wlbr475mw98rsyc0bbr2d5n16m38z253p0dv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#parking_lot@0.12.1": "13r2xk7mnxfc5g0g6dkdxqdqad99j7s7z8zhzz4npw5r0g0v4hip",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#parking_lot_core@0.9.9": "13h0imw1aq86wj28gxkblhkzx6z1gk8q18n0v76qmmj6cliajhjc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#parse-zoneinfo@0.3.0": "0h8g6jy4kckn2gk8sd5adaws180n1ip65xhzw5jxlq4w8ibg41f7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#paste@1.0.14": "0k7d54zz8zrz0623l3xhvws61z5q2wd3hkwim6gylk8212placfy",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pem-rfc7468@0.7.0": "04l4852scl4zdva31c1z6jafbak0ni5pi0j38ml108zwzjdrrcw8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#percent-encoding@1.0.1": "0cgq08v1fvr6bs5fvy390cz830lq4fak8havdasdacxcw790s09i",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.1": "0gi8wgx0dcy8rnv1kywdv98lwcx67hz0a0zwpib5v2i08r88y573",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf@0.11.2": "1p03rsw66l7naqhpgr1a34r9yzi1gv9jh16g3fsk6wrwyfwdiqmd",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf@0.7.24": "066xwv4dr6056a9adlkarwp4n94kbpwngbmd47ngm3cfbyw49nmk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf_codegen@0.11.2": "0nia6h4qfwaypvfch3pnq1nd2qj64dif4a6kai3b7rjrsf49dlz8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf_codegen@0.7.24": "0zjiblicfm0nrmr2xxrs6pnf6zz2394wgch6dcbd8jijkq98agmh",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf_generator@0.11.2": "1c14pjyxbcpwkdgw109f7581cc5fa3fnkzdq1ikvx7mdq9jcrr28",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf_generator@0.7.24": "0qi62gxk3x3whrmw5c4i71406icqk11qmpgln438p6qm7k4lqdh9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf_shared@0.11.2": "0azphb0a330ypqx3qvyffal5saqnks0xvl8rj73jlk3qxxgbkz4h",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#phf_shared@0.7.24": "18371fla0vsj7d6d5rlfb747xbr2in11ar9vgv5qna72bnhp2kr3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pin-project-internal@1.1.3": "01a4l3vb84brv9v7wl71chzxra2kynm6yvcjca66xv3ij6fgsna3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.13": "0n0bwr5qxlf0mhn2xkl36sy55118s9qmvx2yl5f3ixkb007lbywa",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pin-project@1.1.3": "08k4cpy8q3j93qqgnrbzkcgpn7g0a88l4a9nm33kyghpdhffv97x",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pin-utils@0.1.0": "117ir7vslsl2z1a7qzhws4pd01cg2d3338c47swjyvqv2n60v1wb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#piper@0.2.1": "1m45fkdq7q5l9mv3b0ra10qwm0kb67rjp2q8y91958gbqjqk33b6",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pkcs1@0.7.5": "0zz4mil3nchnxljdfs2k5ab1cjqn7kq5lqp62n9qfix01zqvkzy8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pkcs8@0.10.2": "1dx7w21gvn07azszgqd3ryjhyphsrjrmq5mmz1fbxkj5g0vv4l7r",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.27": "0r39ryh1magcq4cz5g9x88jllsnxnhcqr753islvyk4jp9h2h1r6",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#plugin@0.2.6": "1q7nghkpvxxr168y2jnzh3w7qc9vfrby9n7ygy3xpj0bj71hsshs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#png@0.16.8": "1ipl44q3vy4kvx6j296vk7d4v8gvcg203lrkvvixwixq1j98fciw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#png@0.17.10": "0r5a8a25ad0jq2pkp2zbab3wwhpgp6jmdg6d0ybjnw6kilnvyxfx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#polling@2.8.0": "1kixxfq1af1k7gkmmk9yv4j2krpp4fji2r8j4cz6p6d7ihz34bab",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#polling@3.4.0": "052am20b5r03nwhpnjw86rv3dwsdabvb07anv3fqxfbs65r4w19h",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#powerfmt@0.2.0": "14ckj2xdpkhv3h6l5sdmb9f1d57z8hbfpdldjc2vl5givq2y77j3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#ppv-lite86@0.2.17": "1pp6g52aw970adv3x2310n7glqnji96z0a9wiamzw89ibf0ayh2v",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#pretty_env_logger@0.5.0": "076w9dnvcpx6d3mdbkqad8nwnsynb7c8haxmscyrz7g3vga28mw6",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#proc-macro-crate@1.3.1": "069r1k56bvgk0f58dm5swlssfcp79im230affwk6d9ck20g04k3z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#proc-macro-crate@2.0.1": "06jbv5w6s04dbjbwq0iv7zil12ildf3w8dvvb4pqvhig4gm5zp4p",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#proc-macro-error-attr@1.0.4": "0sgq6m5jfmasmwwy8x4mjygx5l7kp8s4j60bv25ckv2j1qc41gm1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#proc-macro-error@1.0.4": "1373bhxaf0pagd8zkyd03kkx6bchzf6g0dkwrwzsnal9z47lj9fs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.78": "1bjak27pqdn4f4ih1c9nr3manzyavsgqmf76ygw9k76q8pb2lhp2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#proptest@1.4.0": "1gzmw40pgmwzb7x6jsyr88z5w151snv5rp1g0dlcp1iw3h9pdd1i",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#qoi@0.4.1": "00c0wkb112annn2wl72ixyd78mf56p4lxkhlmsggx65l3v3n8vbz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#quick-error@1.2.3": "1q6za3v78hsspisc197bg3g7rpc989qycy8ypr8ap8igv10ikl51",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#quote@1.0.35": "1vv8r2ncaz4pqdr78x7f138ka595sp2ncr1sa2plm4zxbsmwj7i9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand@0.3.23": "0v679h38pjjqj5h4md7v2slsvj6686qgcn7p9fbw3h43iwnk1b34",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand@0.4.6": "14qjfv3gggzhnma20k0sc1jf8y6pplsaq7n1j9ls5c8kf2wl0a2m",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand@0.6.5": "1jl4449jcl4wgmzld6ffwqj5gwxrp8zvx8w573g1z368qg6xlwbd",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5": "013l6931nn7gkc23jz5mm3qdhf93jjf0fg64nz2lp4i51qd8vbrl",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.1.1": "1vxwyzs4fy1ffjc8l00fsyygpiss135irjf7nyxgq2v0lqf3lvam",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.3.1": "123x2adin558xbhvqb8w4f6syjsdkmqff8cxwhmjacpsl1ihmhg6",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_core@0.3.1": "0jzdgszfa4bliigiy4hi66k7fs3gfwi2qxn8vik84ph77fwdwvvs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_core@0.4.2": "1p09ynysrq1vcdlmcqnapq4qakl2yd1ng3kxh3qscpx09k2a6cww",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_core@0.6.4": "0b4j2v4cb5krak1pv6kakv4sz6xcwbrmy2zckc32hsigbrwy82zc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_hc@0.1.0": "1i0vl8q5ddvvy0x8hf1zxny393miyzxkwqnw31ifg6p0gdy6fh3v",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_isaac@0.1.1": "027flpjr4znx2csxk7gxb7vrf9c7y5mydmvg5az2afgisp4rgnfy",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_jitter@0.1.4": "16z387y46bfz3csc42zxbjq89vcr1axqacncvv8qhyy93p4xarhi",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_os@0.1.3": "0wahppm0s64gkr2vmhcgwc0lij37in1lgfxg5rbgqlz0l5vgcxbv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_pcg@0.1.2": "0i0bdla18a8x4jn1w0fxsbs3jg7ajllz6azmch1zw33r06dv1ydb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_xorshift@0.1.1": "0p2x8nr00hricpi2m6ca5vysiha7ybnghz79yqhhx6sl4gkfkxyb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rand_xorshift@0.3.0": "13vcag7gmqspzyabfl1gr9ykvxd2142q2agrj8dkyjmfqmgg4nyj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rayon-core@1.12.0": "1vaq0q71yfvcwlmia0iqf6ixj2fibjcf2xjy92n1m1izv1mgpqsw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rayon@1.8.0": "1cfdnvchf7j4cpha5jkcrrsr61li9i9lp5ak7xdq6d3pvc1xn9ww",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rdrand@0.4.0": "1cjq0kwx1bk7jx3kzyciiish5gqsj7620dm43dc52sr8fzmm9037",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#redox_syscall@0.4.1": "1aiifyz5dnybfvkk4cdab9p2kmphag1yad6iknc7aszlxxldf8j7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.3": "0gs8q9yhd3kcg4pr00ag4viqxnh5l7jpyb9fsfr8hzh451w4r02z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.2": "17rd2s8xbiyf6lb4aj2nfi44zqlj98g2ays8zzj2vfs743k79360",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#regex@1.10.2": "0hxkd814n4irind8im5c9am221ri6bprx49nc7yxv02ykhd9a2rq",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#remove_dir_all@0.5.3": "1rzqbsgkmr053bxxl04vmvsd1njyz0nxvly97aip6aa2cmb15k9s",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#reqwest@0.11.23": "0hgvzb7r46656r9vqhl5qk1kbr2xzjb91yr2cb321160ka6sxc9p",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rsa@0.9.6": "1z0d1aavfm0v4pv8jqmqhhvvhvblla1ydzlvwykpc3mkzhj523jx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rustc-demangle@0.1.23": "0xnbk2bmyzshacjm2g1kd4zzv2y2az14bw3sjccq5qkpmsfvn9nn",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rustc-hash@1.1.0": "1qkc5khrmv5pqi5l5ca9p5nl5hs742cagrndhbrlk3dhlrx3zm08",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rustc_version@0.4.0": "0rpk9rcdk405xhbmgclsh4pai0svn49x35aggl4nhbkd4a2zb85z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rustix@0.37.27": "1lidfswa8wbg358yrrkhfvsw0hzlvl540g4lwqszw09sg8vcma7y",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rustix@0.38.28": "05m3vacvbqbg6r6ksmx9k5afpi0lppjdv712crrpsrfax2jp5rbj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rustls-pemfile@1.0.4": "1324n5bcns0rnw6vywr5agff3rwfvzphi7rmbyzwnv6glkhclx0w",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#rusty-fork@0.3.0": "0kxwq5c480gg6q0j3bg4zzyfh2kwmc3v2ba94jw8ncjc8mpcqgfb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#ryu@1.0.16": "0k7b90xr48ag5bzmfjp82rljasw2fx28xr3bg1lrpx7b5sljm3gr",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#safemem@0.3.3": "0wp0d2b2284lw11xhybhaszsczpbq1jbdklkxgifldcknmy3nw7g",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#schannel@0.1.22": "126zy5jb95fc5hvzyjwiq6lc81r08rdcn6affn00ispp9jzk6dqc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#scoped-tls@1.0.1": "15524h04mafihcvfpgxd8f4bgc3k95aclz8grjkg9a0rxcvn9kz1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#scoped_threadpool@0.1.9": "1a26d3lk40s9mrf4imhbik7caahmw2jryhhb6vqv6fplbbgzal8x",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#scopeguard@1.2.0": "0jcz9sd47zlsgcnm1hdw0664krxwb5gczlif4qngj2aif8vky54l",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#security-framework-sys@2.9.1": "0yhciwlsy9dh0ps1gw3197kvyqx1bvc4knrhiznhid6kax196cp9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#security-framework@2.9.2": "1pplxk15s5yxvi2m1sz5xfmjibp96cscdcl432w9jzbk0frlzdh5",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#self_cell@0.10.3": "0pci3zh23b7dg6jmlxbn8k4plb7hcg5jprd1qiz0rp04p1ilskp1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#self_cell@1.0.2": "1rmdglwnd77wcw2gv76finpgzjhkynx422d0jpahrf2fsqn37273",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#semver@1.0.20": "140hmbfa743hbmah1zjf07s8apavhvn04204qjigjiz5w6iscvw3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#serde@0.9.15": "1bsla8l5xr9pp5sirkal6mngxcq6q961km88jvf339j5ff8j7dil",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#serde@1.0.193": "129b0j67594f8qg5cbyi3nyk31y97wrqihi026mba34dwrsrkp95",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.193": "1lwlx2k7wxr1v160kpyqjfabs37gm1yxqg65383rnyrm06jnqms3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.108": "0ssj59s7lpzqh1m50kfzlnrip0p0jg9lmhn4098i33a0mhz7w71x",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#serde_spanned@0.6.5": "1hgh6s3jjwyzhfk3xwb6pnnr1misq9nflwq0f026jafi37s24dpb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#serde_urlencoded@0.7.1": "1zgklbdaysj3230xivihs30qi5vkhigg323a9m62k8jwf4a1qjfk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sha1@0.10.6": "1fnnxlfg08xhkmwf2ahv634as30l1i3xhlhkvxflmasi5nd85gz3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sha2@0.10.8": "1j1x78zk9il95w9iv46dh9wm73r6xrgj32y6lzzw7bxws9dbfgbr",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#signal-hook-registry@1.4.1": "18crkkw5k82bvcx088xlf5g4n3772m24qhzgfan80nda7d3rn8nq",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#signature@2.2.0": "1pi9hd5vqfr3q3k49k37z06p7gs5si0in32qia4mmr1dancr6m3p",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#simd-adler32@0.3.7": "1zkq40c3iajcnr5936gjp9jjh1lpzhy44p3dq3fiw75iwr1w2vfn",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#siphasher@0.2.3": "1b53m53l24lyhr505lwqzrpjyq5qfnic71mynrcfvm43rybf938b",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#siphasher@0.3.11": "03axamhmwsrmh0psdw3gf7c0zc4fyl5yjxfifz9qfka6yhkqid9q",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#slab@0.4.9": "0rxvsgir0qw5lkycrqgb1cxsvxzjv9bmx73bk5y42svnzfba94lg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#smallvec@1.11.2": "0w79x38f7c0np7hqfmzrif9zmn0avjvvm31b166zdk9d1aad1k2d",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#snowflake@1.3.0": "1wadr7bxdxbmkbqkqsvzan6q1h3mxqpxningi3ss3v9jaav7n817",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#socket2@0.4.10": "03ack54dxhgfifzsj14k7qa3r5c9wqy3v6mqhlim99cc03y1cycz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#socket2@0.5.5": "1sgq315f1njky114ip7wcy83qlphv9qclprfjwvxcpfblmcsqpvv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#spin@0.5.2": "0b84m6dbzrwf2kxylnw82d3dr8w06av7rfkr8s85fb5f43rwyqvf",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#spin@0.9.8": "0rvam5r0p3a6qhc18scqpvpgb3ckzyqxpgdfyjnghh8ja7byi039",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#spki@0.7.3": "17fj8k5fmx4w9mp27l970clrh5qa7r5sjdvbsln987xhb34dc7nr",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlformat@0.2.3": "0v0p70wjdshj18zgjjac9xlx8hmpx33xhq7g8x9rg4s4gjyvg0ff",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlx-core@0.7.3": "1gdz44yb9qwxv4xl4hv6w4vbqx0zzdlzsf9j9gcj1qir6wy0ljyq",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlx-macros-core@0.7.3": "0h88wahkxa6nam536lhwr1y0yxlr6la8b1x0hs0n88v790clbgfh",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlx-macros@0.7.3": "19gjwisiym07q7ibkp9nkvvbywjh0r5rc572msvzyzadvh01r5l9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlx-mysql@0.7.3": "190ygz5a3pqcd9vvqjv2i4r1xh8vi53j4272yrld07zpblwrawg3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlx-postgres@0.7.3": "090wm9s6mm53ggn1xwr183cnn8yxly8rgcksdk4hrlfcnz1hmb6n",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlx-sqlite@0.7.3": "143laha7wf8dmi0xwycwqmvxdcnb25dq7jnqrsgvmis8v6vpc291",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#sqlx@0.7.3": "1kv3hyx7izmmsjqh3l47zrfhjlcblpg20cvnk7pr8dm7klkkr86v",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#stringprep@0.1.4": "1rkfsf7riynsmqj3hbldfrvmna0i9chx2sz39qdpl40s4d7dfhdv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#strsim@0.10.0": "08s69r4rcrahwnickvi0kq49z524ci50capybln83mg6b473qivk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#subtle@2.5.0": "1g2yjs7gffgmdvkkq0wrrh0pxds3q0dv6dhkw9cdpbib656xdkc1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#syn@1.0.109": "0ds2if4600bd59wsv7jjgfkayfzy3hnazs394kz6zdkmna8l3dkj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#syn@2.0.48": "0gqgfygmrxmp8q32lia9p294kdd501ybn6kn2h4gqza0irik2d8g",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#system-configuration-sys@0.5.0": "1jckxvdr37bay3i9v52izgy52dg690x5xfg3hd394sv2xf4b2px7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#system-configuration@0.5.1": "1rz0r30xn7fiyqay2dvzfy56cvaa3km74hnbz2d72p97bkf3lfms",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#system-deps@6.2.0": "0c836abhh3k8yn5ymg8wx383ay7n731gkrbbp3gma352yq7mhb9a",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.12.12": "02lk65ik5ffb8vl9qzq02v0df8kxrp16zih78a33mji49789zhql",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tempdir@0.3.7": "1n5n86zxpgd85y0mswrp5cfdisizq2rv3la906g6ipyc03xvbwhm",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tempfile@3.8.1": "1r88v07zdafzf46y63vs39rmzwl4vqd4g2c5qarz9mqa8nnavwby",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#termcolor@1.4.0": "0jfllflbxxffghlq6gx4csv0bv0qv77943dcx01h9zssy39w66zz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#thiserror-impl@1.0.51": "1ps9ylhlk2vn19fv3cxp40j3wcg1xmb117g2z2fbf4vmg2bj4x01",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#thiserror@1.0.51": "1drvyim21w5sga3izvnvivrdp06l2c24xwbhp0vg1mhn2iz2277i",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tiff@0.6.1": "0ds48vs919ccxa3fv1www7788pzkvpg434ilqkq7sjb5dmqg8lws",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tiff@0.9.0": "04b2fd3clxm0pmdlfip8xj594zyrsfwmh641i6x1gfiz9l7jn5vd",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#time-core@0.1.2": "1wx3qizcihw6z151hywfzzyd1y5dl804ydyxci6qm07vbakpr4pg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#time-macros@0.2.16": "0gx4ngf5g7ydqa8lf7kh9sy72rd4dhvpi31y1jvswi0288rpw696",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#time@0.1.45": "0nl0pzv9yf56djy8y5dx25nka5pr2q1ivlandb3d24pksgx7ly8v",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#time@0.3.31": "0gjqcdsdbh0r5vi4c2vrj5a6prdviapx731wwn07cvpqqd1blmzn",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tinystr@0.7.5": "1khf3j95bwwksj2hw76nlvwlwpwi4d1j421lj6x35arqqprjph43",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tinyvec@1.6.0": "0l6bl2h62a5m44jdnpn7lmj14rd44via8180i7121fvm73mmrk47",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tinyvec_macros@0.1.1": "081gag86208sc3y6sdkshgw3vysm5d34p431dzw0bshz66ncng0z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tokio-macros@2.2.0": "0fwjy4vdx1h9pi4g2nml72wi0fr27b5m954p13ji9anyy8l1x2jv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tokio-native-tls@0.3.1": "1wkfg6zn85zckmv4im7mv20ca6b1vmlib5xwz9p7g19wjfmpdbmv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tokio-stream@0.1.14": "0hi8hcwavh5sdi1ivc9qc4yvyr32f153c212dpd7sb366y6rhz1r",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tokio-tungstenite@0.20.1": "0v1v24l27hxi5hlchs7hfd5rgzi167x0ygbw220nvq0w5b5msb91",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tokio-util@0.7.10": "058y6x4mf0fsqji9rfyb77qbfyc50y4pk2spqgj6xsyr693z66al",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tokio@1.35.1": "01613rkziqp812a288ga65aqygs254wgajdi57v8brivjkx4x6y8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#toml@0.8.2": "0g9ysjaqvm2mv8q85xpqfn7hi710hj24sd56k49wyddvvyq8lp8q",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#toml_datetime@0.6.3": "0jsy7v8bdvmzsci6imj8fzgd255fmy5fzp6zsri14yrry7i77nkw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#toml_edit@0.19.15": "08bl7rp5g6jwmfpad9s8jpw8wjrciadpnbaswgywpr9hv9qbfnqv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#toml_edit@0.20.2": "0f7k5svmxw98fhi28jpcyv7ldr2s3c867pjbji65bdxjpd44svir",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.2": "0lmfzmmvid2yp2l36mbavhmqgsvzqf7r2wiwz73ml4xmwaf1rg5n",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tracing-attributes@0.1.27": "1rvb5dn9z6d0xdj14r403z0af0bbaqhg02hq4jc97g5wds6lqw1l",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tracing-core@0.1.32": "0m5aglin3cdwxpvbg6kz0r9r0k31j48n0kcfwsp6l49z26k3svf0",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.40": "1vv48dac9zgj9650pg2b4d0j3w6f3x9gbggf43scq5hrlysklln3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#traitobject@0.1.0": "0yb0n8822mr59j200fyr2fxgzzgqljyxflx9y8bdy3rlaqngilgg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#try-lock@0.2.5": "0jqijrrvm1pyq34zn1jmy2vihd4jcrjlvsh4alkjahhssjnsn8g4",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#tungstenite@0.20.1": "1fbgcv3h4h1bhhf5sqbwqsp7jnc44bi4m41sgmhzdsk2zl8aqgcy",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#type-map@0.4.0": "0ilsqq7pcl3k9ggxv2x5fbxxfd6x7ljsndrhc38jmjwnbr63dlxn",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#typeable@0.1.2": "11w8dywgnm32hb291izjvh4zjd037ccnkk77ahk63l913zwzc40l",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#typemap@0.3.3": "1xm1gbvz9qisj1l6d36hrl9pw8imr8ngs6qyanjnsad3h0yfcfv5",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#typenum@1.17.0": "09dqxv69m9lj9zvv6xw5vxaqx15ps0vxyy5myg33i0kbqvq0pzs2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#typeshare-annotation@1.0.2": "1adpfhyz3lqjjbq2ym69mv62ymqyd5651gxlqdy8aa446l70srzw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#typeshare@1.0.1": "1mi7snkx2b4g84x8vx38v1myg5r6g48c865j0nz5zcsc8lpilkgl",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unarray@0.1.4": "154smf048k84prsdgh09nkm2n0w0336v84jd4zikyn6v6jrqbspa",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unic-langid-impl@0.9.4": "1ijvqmsrg6qw3b1h9bh537pvwk2jn2kl6ck3z3qlxspxcch5mmab",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unic-langid@0.9.4": "05pm5p3j29c9jw9a4dr3v64g3x6g3zh37splj47i7vclszk251r3",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unicase@1.4.2": "0cwazh4qsmm9msckjk86zc1z35xg7hjxjykrgjalzdv367w6aivz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unicase@2.7.0": "12gd74j79f94k4clxpf06l99wiv4p30wjr0qm04ihqk9zgdd9lpp",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unicode-bidi@0.3.14": "05i4ps31vskq1wdp8yf315fxivyh1frijly9d4gb5clygbr2h9bg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12": "0jzf1znfpb2gx8nr8mvmyqs1crnv79l57nxnbiszc7xf7ynbjm1k",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unicode-normalization@0.1.22": "08d95g7b1irc578b2iyhzv4xhsa4pfvwsqxcl9lbcpabzkq16msw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unicode-segmentation@1.10.1": "0dky2hm5k51xy11hc3nk85p533rvghd462b6i0c532b7hl4j9mhx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unicode_categories@0.1.1": "0kp1d7fryxxm7hqywbk88yb9d1avsam9sg76xh36k5qx2arj9v1r",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#unsafe-any@0.4.2": "0zwwphsqkw5qaiqmjwngnfpv9ym85qcsyj7adip9qplzjzbn00zk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#url@1.7.2": "0nim1c90mxpi9wgdw2xh8dqd72vlklwlzam436akcrhjac6pqknx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#url@2.5.0": "0cs65961miawncdg2z20171w0vqrmraswv2ihdpd8lxp7cp31rii",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#urlencoding@2.1.3": "1nj99jp37k47n0hvaz5fvz7z6jd0sb4ppvfy3nphr1zbnyixpy6s",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#utf-8@0.7.6": "1a9ns3fvgird0snjkd3wbdhwd3zdpc2h5gpyybrfr6ra5pkqxk09",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#utf8parse@0.2.1": "02ip1a0az0qmc2786vxk2nqwsgcwf17d3a38fkf0q7hrmwh9c6vi",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#uuid@0.4.0": "0cdj2v6v2yy3zyisij69waksd17cyir1n58kwyk1n622105wbzkw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#uuid@0.8.2": "1dy4ldcp7rnzjy56dxh7d2sgrcvn4q77y0a8r0a48946h66zjp5w",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#uuid@1.6.1": "0q45jxahvysldn3iy04m8xmr8hgig80855y9gq9di8x72v7myfay",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#value-bag@1.7.0": "02r8wccrzi3bzlkrslkcfw9pwp8kwif9szif2i9arn9dzqx44vhj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15": "09i4nf5y8lig6xgj3f7fyrvzd3nlaw4znrihw8psidvv5yk4xkdc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#version-compare@0.1.1": "0acg4pmjdbmclg0m7yhijn979mdy66z3k8qrcnvn634f1gy456jp",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#version_check@0.1.5": "1pf91pvj8n6akh7w6j5ypka6aqz08b3qpzgs0ak2kjf4frkiljwi",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.4": "0gs8grwdlgh0xq660d7wr80x14vxbizmd8dbp29p2pdncx8lp1s9",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wait-timeout@0.2.0": "1xpkk0j5l9pfmjfh1pi0i89invlavfrd9av5xp0zhxgb29dhy84z",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#waker-fn@1.1.1": "142n74wlmpwcazfb5v7vhnzj3lb3r97qy8mzpjdpg345aizm3i7k",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#want@0.3.1": "03hbfrnvqqdchb5kgxyavb9jabwza0dmh2vw5kg0dq8rxl57d9xz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#warp@0.3.6": "0sfimrpxkyka1mavfhg5wa4x977qs8vyxa510c627w9zw0i2xsf1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasi@0.10.0+wasi-snapshot-preview1": "07y3l8mzfzzz4cj09c8y90yak4hpsi9g7pllyzpr6xvwrabka50s",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasi@0.11.0+wasi-snapshot-preview1": "08z4hxwkpdpalxjps1ai9y7ihin26y9f476i53dv98v45gkqg3cw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-backend@0.2.89": "09l8lyylsdssz993h4fzja69zpvpykaw84fivs210fjgwqjzcmhv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-futures@0.4.39": "04lsxpw4jqfwh7c0crzx0smj52nvwp1w3bh4098sq90149da2dmc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro-support@0.2.89": "10sj1gr2naxv5q116yjb929hhpvz45dxbkvyk8hyc2lknzy85szh",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro@0.2.89": "1cl2w7k5jn2jbd5kx613c8k8vjvda22hfgcgx7y2mk93fbrxnqh1",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-shared@0.2.89": "17s5rppad113c6ggkaq8c3cg7a3zz15i78wxcg6mcl1n15iv7fbs",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen@0.2.89": "0kh6akdldy13z9xqj0skz6b4npq1d98bjkgzb8ccq59hibvd9l0f",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#web-sys@0.3.66": "03q1z22djv5ncqkyydcvnchmdsl5gvnyzcyixkxnifw6xi24mhjh",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#weezl@0.1.7": "1frdbq6y5jn2j93i20hc80swpkj30p1wffwxj1nr4fp09m6id4wi",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#whoami@1.4.1": "0l6ca9pl92wmngsn1dh9ih716v216nmn2zvcn94k04x9p1b3gz12",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#winapi-i686-pc-windows-gnu@0.4.0": "1dmpa6mvcvzz16zg6d5vrfy4bxgg541wxrcip7cnshi06v38ffxc",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#winapi-util@0.1.6": "15i5lm39wd44004i9d5qspry2cynkrpvwzghr6s2c3dsk28nz7pj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#winapi-x86_64-pc-windows-gnu@0.4.0": "0gqq64czqb64kskjryj8isp62m2sgvx25yyj3kpc2myh85w24bki",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#winapi@0.3.9": "06gl025x418lchw1wxj64ycr7gha83m44cjr5sarhynd9xkrm0sw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows-core@0.51.1": "0r1f57hsshsghjyc7ypp2s0i78f7b1vr93w68sdb8baxyf2czy7i",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows-sys@0.48.0": "1aan23v5gs7gya1lc46hqn9mdh8yph3fhxmhxlw36pn6pqc28zb7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows-sys@0.52.0": "0gd3v4ji88490zgb6b5mq5zgbvwv7zx1ibn8v3x83rwcdbryaar8",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows-targets@0.48.5": "034ljxqshifs1lan89xwpcy1hp0lhdh4b5n0d2z4fwjx2piacbws",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows-targets@0.52.0": "1kg7a27ynzw8zz3krdgy6w5gbqcji27j1sz4p7xk2j5j8082064a",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_gnullvm@0.48.5": "1n05v7qblg1ci3i567inc7xrkmywczxrs1z3lj3rkkxw18py6f1b",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_gnullvm@0.52.0": "1shmn1kbdc0bpphcxz0vlph96bxz0h1jlmh93s9agf2dbpin8xyb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_msvc@0.48.5": "1g5l4ry968p73g6bg6jgyvy9lb8fyhcs54067yzxpcpkf44k2dfw",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_msvc@0.52.0": "1vvmy1ypvzdvxn9yf0b8ygfl85gl2gpcyvsvqppsmlpisil07amv",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnu@0.48.5": "0gklnglwd9ilqx7ac3cn8hbhkraqisd0n83jxzf9837nvvkiand7",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnu@0.52.0": "04zkglz4p3pjsns5gbz85v4s5aw102raz4spj4b0lmm33z5kg1m2",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_i686_msvc@0.48.5": "01m4rik437dl9rdf0ndnm2syh10hizvq0dajdkv2fjqcywrw4mcg",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_i686_msvc@0.52.0": "16kvmbvx0vr0zbgnaz6nsks9ycvfh5xp05bjrhq65kj623iyirgz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnu@0.48.5": "13kiqqcvz2vnyxzydjh73hwgigsdr2z1xpzx313kxll34nyhmm2k",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnu@0.52.0": "1zdy4qn178sil5sdm63lm7f0kkcjg6gvdwmcprd2yjmwn8ns6vrx",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnullvm@0.48.5": "1k24810wfbgz8k48c2yknqjmiigmql6kk3knmddkv8k8g1v54yqb",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnullvm@0.52.0": "17lllq4l2k1lqgcnw1cccphxp9vs7inq99kjlm2lfl9zklg7wr8s",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_msvc@0.48.5": "0f4mdp895kkjh9zv8dxvn4pc10xr7839lf5pa9l0193i2pkgr57d",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_msvc@0.52.0": "012wfq37f18c09ij5m6rniw7xxn5fcvrxbqd0wd8vgnl3hfn9yfz",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#winnow@0.5.30": "1ifj9vnqna5qp0d7nb9mrinzf8j7zi1m0gv75870vm91jyw3sp4v",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#winreg@0.50.0": "1cddmp929k882mdh6i9f2as848f13qqna6czwsqzkh1pqnr5fkjj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.7.31": "06k0zk4x4n9s1blgxmxqb1g81y8q334aayx61gyy6v9y1dajkhdk",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.7.31": "0gcfyrmlrhmsz16qxjp2qzr6vixyaw1p04zl28f08lxkvfz62h0w",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#zeroize@1.7.0": "0bfvby7k9pdp6623p98yz2irqnamcyzpn7zh20nqmdn68b0lwnsj",
|
||||
"registry+https://github.com/rust-lang/crates.io-index#zune-inflate@0.2.54": "00kg24jh3zqa3i6rg6yksnb71bch9yi1casqydl00s7nw8pk7avk"
|
||||
}
|
|
@ -14,6 +14,7 @@ sgf = { path = "../../sgf" }
|
|||
grid = { version = "0.9" }
|
||||
serde_json = { version = "1" }
|
||||
serde = { version = "1", features = [ "derive" ] }
|
||||
nary_tree = { version = "0.4" }
|
||||
thiserror = { version = "1" }
|
||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ impl From<HotseatPlayerRequest> for Player {
|
|||
}
|
||||
*/
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CoreResponse {
|
||||
Library(library::LibraryResponse),
|
||||
Settings(settings::SettingsResponse),
|
||||
|
|
|
@ -42,7 +42,8 @@ impl Database {
|
|||
.unwrap();
|
||||
match parse_sgf(&buffer) {
|
||||
Ok(sgfs) => {
|
||||
let mut sgfs = sgfs.into_iter().flatten().collect::<Vec<sgf::GameRecord>>();
|
||||
let mut sgfs =
|
||||
sgfs.into_iter().flatten().collect::<Vec<sgf::GameRecord>>();
|
||||
games.append(&mut sgfs);
|
||||
}
|
||||
Err(err) => println!("Error parsing {:?}: {:?}", entry.path(), err),
|
||||
|
|
|
@ -29,7 +29,9 @@ pub mod library;
|
|||
pub mod settings;
|
||||
|
||||
mod types;
|
||||
pub use types::{BoardError, Color, Config, ConfigOption, LibraryPath, Player, Rank, Size, Tree};
|
||||
pub use types::{
|
||||
BoardError, Color, Config, ConfigOption, DepthTree, LibraryPath, Player, Rank, Size,
|
||||
};
|
||||
|
||||
mod view_models;
|
||||
pub use view_models::GameReviewViewModel;
|
||||
|
|
|
@ -14,18 +14,18 @@ General Public License for more details.
|
|||
You should have received a copy of the GNU General Public License along with On the Grid. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::{Core};
|
||||
use crate::Core;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sgf::GameRecord;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum LibraryRequest {
|
||||
ListGames
|
||||
ListGames,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum LibraryResponse {
|
||||
Games(Vec<GameRecord>)
|
||||
Games(Vec<GameRecord>),
|
||||
}
|
||||
|
||||
async fn handle_list_games(model: &Core) -> LibraryResponse {
|
||||
|
@ -39,10 +39,8 @@ async fn handle_list_games(model: &Core) -> LibraryResponse {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn handle(model: &Core, request: LibraryRequest) -> LibraryResponse {
|
||||
match request {
|
||||
LibraryRequest::ListGames => handle_list_games(model).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use crate::goban::{Coordinate, Goban};
|
||||
use config::define_config;
|
||||
use config_derive::ConfigOption;
|
||||
use nary_tree::NodeRef;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sgf::GameNode;
|
||||
use std::{cell::RefCell, collections::VecDeque, fmt, path::PathBuf, time::Duration};
|
||||
use sgf::GameTree;
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque}, fmt, ops::Deref, path::PathBuf, time::Duration
|
||||
};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
define_config! {
|
||||
LibraryPath(LibraryPath),
|
||||
|
@ -229,6 +231,7 @@ impl GameState {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// To properly generate a tree, I need to know how deep to go. Then I can backtrace. Each node
|
||||
// needs to have a depth. Given a tree, the depth of the node is just the distance from the root.
|
||||
// This seems obvious, but I had to write it to discover how important that fact was.
|
||||
|
@ -238,31 +241,78 @@ impl GameState {
|
|||
pub struct Tree<T> {
|
||||
nodes: Vec<Node<T>>,
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Node<T> {
|
||||
pub id: usize,
|
||||
pub content: T,
|
||||
parent: Option<usize>,
|
||||
depth: usize,
|
||||
width: RefCell<Option<usize>>,
|
||||
children: Vec<usize>,
|
||||
// https://llimllib.github.io/pymag-trees/
|
||||
// I want to take advantage of the Wetherell Shannon algorithm, but I want some variations. In
|
||||
// their diagram, they got a tree that looks like this.
|
||||
//
|
||||
// O
|
||||
// |\
|
||||
// O O
|
||||
// |\ \ \
|
||||
// O O O O
|
||||
// |\ |\
|
||||
// O O O O
|
||||
//
|
||||
// In the same circumstance, what I want is this:
|
||||
//
|
||||
// O--
|
||||
// | \
|
||||
// O O
|
||||
// |\ |\
|
||||
// O O O O
|
||||
// |\
|
||||
// O O
|
||||
//
|
||||
// In order to keep things from being overly smooshed, I want to ensure that if a branch overlaps
|
||||
// with another branch, there is some extra drawing space. This might actually be similar to adding
|
||||
// the principal that "A parent should be centered over its children".
|
||||
//
|
||||
// So, given a tree, I need to know how many children exist at each level. Then I build parents
|
||||
// atop the children. At level 3, I have four children, and that happens to be the maximum width of
|
||||
// the graph.
|
||||
//
|
||||
// A bottom-up traversal:
|
||||
// - Figure out the number of nodes at each depth
|
||||
|
||||
pub struct DepthTree(nary_tree::Tree<SizeNode>);
|
||||
|
||||
impl Deref for DepthTree {
|
||||
type Target = nary_tree::Tree<SizeNode>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Tree<T> {
|
||||
fn new(root: T) -> Self {
|
||||
Tree {
|
||||
nodes: vec![Node {
|
||||
id: 0,
|
||||
content: root,
|
||||
parent: None,
|
||||
depth: 0,
|
||||
width: RefCell::new(None),
|
||||
children: vec![],
|
||||
}],
|
||||
}
|
||||
impl Default for DepthTree {
|
||||
fn default() -> Self {
|
||||
Self(nary_tree::Tree::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SizeNode {
|
||||
/// Use this to map back to the node in the original game tree. This way we know how to
|
||||
/// correspond from a node in the review tree back to there.
|
||||
pub game_node_id: nary_tree::NodeId,
|
||||
|
||||
/// How deep into the tree is this node?
|
||||
depth: usize,
|
||||
|
||||
/// How far from the leftmost margin is this node?
|
||||
width: usize,
|
||||
}
|
||||
|
||||
impl SizeNode {
|
||||
pub fn position(&self) -> (usize, usize) {
|
||||
(self.depth, self.width)
|
||||
}
|
||||
}
|
||||
|
||||
impl DepthTree {
|
||||
/*
|
||||
pub fn node(&self, idx: usize) -> &T {
|
||||
&self.nodes[idx].content
|
||||
}
|
||||
|
@ -294,12 +344,21 @@ impl<T> Tree<T> {
|
|||
parent.children.push(next_idx);
|
||||
next_idx
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn max_depth(&self) -> usize {
|
||||
self.nodes.iter().fold(
|
||||
0,
|
||||
|max, node| if node.depth > max { node.depth } else { max },
|
||||
)
|
||||
self.0
|
||||
.root()
|
||||
.unwrap()
|
||||
.traverse_pre_order()
|
||||
.fold(0, |max, node| {
|
||||
println!("node depth: {}", node.data().depth);
|
||||
if node.data().depth > max {
|
||||
node.data().depth
|
||||
} else {
|
||||
max
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Since I know the width of a node, now I want to figure out its placement in the larger
|
||||
|
@ -317,7 +376,9 @@ impl<T> Tree<T> {
|
|||
// amounts to the position of the parent node.
|
||||
//
|
||||
// When drawing nodes, I don't know how to persist the level of indent.
|
||||
pub fn position(&self, idx: usize) -> (usize, usize) {
|
||||
|
||||
// unimplemented!()
|
||||
/*
|
||||
let node = &self.nodes[idx];
|
||||
match node.parent {
|
||||
Some(parent_idx) => {
|
||||
|
@ -334,8 +395,9 @@ impl<T> Tree<T> {
|
|||
// Root nodes won't have a parent, so just put them in the first column
|
||||
None => (0, 0),
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Given a node, do a postorder traversal to figure out the width of the node based on all of
|
||||
// its children. This is equivalent to the widest of all of its children at all depths.
|
||||
//
|
||||
|
@ -361,14 +423,100 @@ impl<T> Tree<T> {
|
|||
|
||||
width
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn bfs_iter(&self) -> BFSIter<T> {
|
||||
pub fn bfs_iter(&self) -> BFSIter<'_, SizeNode> {
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(&self.nodes[0]);
|
||||
BFSIter { tree: self, queue }
|
||||
queue.push_back(self.0.root().unwrap());
|
||||
BFSIter { queue }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a GameTree> for DepthTree {
|
||||
fn from(tree: &'a GameTree) -> Self {
|
||||
// Like in the conversion from SGF to GameTree, I need to traverse the entire tree one node
|
||||
// at a time, keeping track of node ids as we go. I'm going to go with a depth-first
|
||||
// traversal. When generating each node, I think I want to generate all of the details of
|
||||
// the node as we go.
|
||||
let source_root_node = tree.root();
|
||||
match source_root_node {
|
||||
Some(source_root_node) => {
|
||||
// Do the real work
|
||||
// The id_map indexes from the source tree to the destination tree. Reverse
|
||||
// indexing is accomplished by looking at the node_id in a node in the destination
|
||||
// tree.
|
||||
let mut id_map: HashMap<nary_tree::NodeId, nary_tree::NodeId> = HashMap::new();
|
||||
let mut tree = nary_tree::Tree::new();
|
||||
|
||||
let mut iter = source_root_node.traverse_pre_order();
|
||||
let _ = iter.next().unwrap(); // we already know that the first element to be
|
||||
// returned is the root node, and that the root node
|
||||
// already exists. Otherwise we wouldn't even be in
|
||||
// this branch.
|
||||
|
||||
let dest_root_id = tree.set_root(SizeNode {
|
||||
game_node_id: source_root_node.node_id(),
|
||||
depth: 0,
|
||||
width: 0,
|
||||
});
|
||||
|
||||
id_map.insert(source_root_node.node_id(), dest_root_id);
|
||||
|
||||
for source_node in iter {
|
||||
let dest_parent_id = id_map
|
||||
.get(&source_node.parent().unwrap().node_id())
|
||||
.unwrap();
|
||||
|
||||
let mut dest_parent = tree.get_mut(*dest_parent_id).unwrap();
|
||||
|
||||
let new_depth_node = SizeNode {
|
||||
game_node_id: source_node.node_id(),
|
||||
depth: 1 + dest_parent.data().depth,
|
||||
width: dest_parent.data().width,
|
||||
};
|
||||
|
||||
let new_node_id = dest_parent.append(new_depth_node).node_id();
|
||||
|
||||
match tree
|
||||
.get(new_node_id)
|
||||
.unwrap()
|
||||
.prev_sibling()
|
||||
.map(|node| node.data().width)
|
||||
{
|
||||
None => {}
|
||||
Some(previous_width) => {
|
||||
let mut new_node = tree.get_mut(new_node_id).unwrap();
|
||||
new_node.data().width = previous_width + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
let new_node = tree.get_mut(*dest_parent_id).unwrap().append(new_depth_node);
|
||||
let previous_node = new_node.prev_sibling();
|
||||
|
||||
match previous_node {
|
||||
None => {}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
match dest_noderef.prev_sibling() {
|
||||
None => {}
|
||||
Some(mut node) => { dest_noderef.data().width = node.data().width + 1 }
|
||||
}
|
||||
*/
|
||||
|
||||
id_map.insert(source_node.node_id(), new_node_id);
|
||||
}
|
||||
|
||||
Self(tree)
|
||||
}
|
||||
None => Self::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<'a> From<&'a GameNode> for Tree<Uuid> {
|
||||
fn from(root: &'a GameNode) -> Self {
|
||||
fn add_subtree(tree: &mut Tree<Uuid>, parent_idx: usize, node: &GameNode) {
|
||||
|
@ -398,22 +546,21 @@ impl<'a> From<&'a GameNode> for Tree<Uuid> {
|
|||
tree
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub struct BFSIter<'a, T> {
|
||||
tree: &'a Tree<T>,
|
||||
queue: VecDeque<&'a Node<T>>,
|
||||
queue: VecDeque<nary_tree::NodeRef<'a, T>>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for BFSIter<'a, T> {
|
||||
type Item = &'a Node<T>;
|
||||
type Item = NodeRef<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let retval = self.queue.pop_front();
|
||||
if let Some(retval) = retval {
|
||||
if let Some(ref retval) = retval {
|
||||
retval
|
||||
.children
|
||||
.iter()
|
||||
.for_each(|idx| self.queue.push_back(&self.tree.nodes[*idx]));
|
||||
.children()
|
||||
.for_each(|noderef| self.queue.push_back(noderef));
|
||||
}
|
||||
retval
|
||||
}
|
||||
|
@ -422,8 +569,8 @@ impl<'a, T> Iterator for BFSIter<'a, T> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use cool_asserts::assert_matches;
|
||||
use sgf::{Move, MoveNode};
|
||||
// use sgf::{GameRecord, GameTree, GameType, Move, MoveNode};
|
||||
use sgf::{GameNode, GameTree, Move, MoveNode};
|
||||
|
||||
#[test]
|
||||
fn current_player_changes_after_move() {
|
||||
|
@ -482,116 +629,131 @@ mod test {
|
|||
// B G H
|
||||
// C I
|
||||
// D E F
|
||||
fn branching_tree() -> GameTree {
|
||||
let mut game_tree = GameTree::default();
|
||||
let node_a = game_tree.set_root(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)));
|
||||
|
||||
let node_b = game_tree
|
||||
.get_mut(node_a)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
let node_c = game_tree
|
||||
.get_mut(node_b)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
let _node_d = game_tree
|
||||
.get_mut(node_c)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
let _node_e = game_tree
|
||||
.get_mut(node_c)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
let _node_f = game_tree
|
||||
.get_mut(node_c)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
let _node_g = game_tree
|
||||
.get_mut(node_a)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
let node_h = game_tree
|
||||
.get_mut(node_a)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
let _ = game_tree
|
||||
.get_mut(node_h)
|
||||
.unwrap()
|
||||
.append(GameNode::MoveNode(MoveNode::new(
|
||||
sgf::Color::Black,
|
||||
Move::Move("dp".to_owned()),
|
||||
)))
|
||||
.node_id();
|
||||
|
||||
game_tree
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_calculate_depth_from_game_tree() {
|
||||
let mut node_a = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_b = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_c = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_d = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_e = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_f = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_g = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_h = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_i = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
|
||||
node_c.children.push(GameNode::MoveNode(node_d));
|
||||
node_c.children.push(GameNode::MoveNode(node_e));
|
||||
node_c.children.push(GameNode::MoveNode(node_f));
|
||||
|
||||
node_b.children.push(GameNode::MoveNode(node_c));
|
||||
|
||||
node_h.children.push(GameNode::MoveNode(node_i));
|
||||
|
||||
node_a.children.push(GameNode::MoveNode(node_b));
|
||||
node_a.children.push(GameNode::MoveNode(node_g));
|
||||
node_a.children.push(GameNode::MoveNode(node_h));
|
||||
|
||||
let game_tree = GameNode::MoveNode(node_a);
|
||||
|
||||
let tree = Tree::from(&game_tree);
|
||||
|
||||
let game_tree = branching_tree();
|
||||
let tree = DepthTree::from(&game_tree);
|
||||
assert_eq!(
|
||||
game_tree.root().unwrap().traverse_pre_order().count(),
|
||||
tree.0.root().unwrap().traverse_pre_order().count()
|
||||
);
|
||||
assert_eq!(tree.max_depth(), 3);
|
||||
}
|
||||
|
||||
// A
|
||||
// B G H
|
||||
// C I
|
||||
// D E F
|
||||
#[test]
|
||||
fn it_calculates_horizontal_position_of_nodes() {
|
||||
let mut node_a = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_b = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_c = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_d = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_e = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_f = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_g = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_h = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_i = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let game_tree = branching_tree();
|
||||
let tree = DepthTree::from(&game_tree);
|
||||
|
||||
node_c.children.push(GameNode::MoveNode(node_d));
|
||||
node_c.children.push(GameNode::MoveNode(node_e));
|
||||
node_c.children.push(GameNode::MoveNode(node_f));
|
||||
let node_a = tree.root().unwrap();
|
||||
assert_eq!(node_a.data().position(), (0, 0));
|
||||
|
||||
node_b.children.push(GameNode::MoveNode(node_c));
|
||||
let node_b = node_a.first_child().unwrap();
|
||||
assert_eq!(node_b.data().position(), (1, 0));
|
||||
let node_g = node_b.next_sibling().unwrap();
|
||||
assert_eq!(node_g.data().position(), (1, 1));
|
||||
let node_h = node_g.next_sibling().unwrap();
|
||||
assert_eq!(node_h.data().position(), (1, 2));
|
||||
|
||||
node_h.children.push(GameNode::MoveNode(node_i));
|
||||
let node_c = node_b.first_child().unwrap();
|
||||
assert_eq!(node_c.data().position(), (2, 0));
|
||||
|
||||
node_a.children.push(GameNode::MoveNode(node_b));
|
||||
node_a.children.push(GameNode::MoveNode(node_g));
|
||||
node_a.children.push(GameNode::MoveNode(node_h));
|
||||
let node_d = node_c.first_child().unwrap();
|
||||
assert_eq!(node_d.data().position(), (3, 0));
|
||||
|
||||
let game_tree = GameNode::MoveNode(node_a);
|
||||
let node_i = node_h.first_child().unwrap();
|
||||
assert_eq!(node_i.data().position(), (2, 2));
|
||||
|
||||
let tree = Tree::from(&game_tree);
|
||||
|
||||
assert_eq!(tree.position(2), (2, 0));
|
||||
assert_eq!(tree.position(1), (1, 0));
|
||||
assert_eq!(tree.position(0), (0, 0));
|
||||
assert_eq!(tree.position(4), (3, 1));
|
||||
assert_eq!(tree.position(5), (3, 2));
|
||||
assert_eq!(tree.position(6), (1, 3));
|
||||
assert_eq!(tree.position(7), (1, 4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn breadth_first_iter() {
|
||||
let mut node_a = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_b = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_c = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_d = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_e = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_f = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_g = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_h = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_i = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||
|
||||
node_c.children.push(GameNode::MoveNode(node_d.clone()));
|
||||
node_c.children.push(GameNode::MoveNode(node_e.clone()));
|
||||
node_c.children.push(GameNode::MoveNode(node_f.clone()));
|
||||
|
||||
node_b.children.push(GameNode::MoveNode(node_c.clone()));
|
||||
|
||||
node_h.children.push(GameNode::MoveNode(node_i.clone()));
|
||||
|
||||
node_a.children.push(GameNode::MoveNode(node_b.clone()));
|
||||
node_a.children.push(GameNode::MoveNode(node_g.clone()));
|
||||
node_a.children.push(GameNode::MoveNode(node_h.clone()));
|
||||
|
||||
let game_tree = GameNode::MoveNode(node_a.clone());
|
||||
|
||||
let tree = Tree::from(&game_tree);
|
||||
|
||||
let mut iter = tree.bfs_iter();
|
||||
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_a.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_b.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_g.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_h.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_c.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_i.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_d.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_e.id));
|
||||
assert_matches!(iter.next(), Some(Node { content: uuid, .. }) => assert_eq!(*uuid, node_f.id));
|
||||
/*
|
||||
assert_eq!(tree.position(test_tree.node_c), (2, 0));
|
||||
assert_eq!(tree.position(test_tree.node_b), (1, 0));
|
||||
assert_eq!(tree.position(test_tree.node_a), (0, 0));
|
||||
assert_eq!(tree.position(test_tree.node_d), (3, 1));
|
||||
assert_eq!(tree.position(test_tree.node_e), (3, 2));
|
||||
assert_eq!(tree.position(test_tree.node_f), (1, 3));
|
||||
assert_eq!(tree.position(test_tree.node_g), (1, 4));
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,15 @@ You should have received a copy of the GNU General Public License along with On
|
|||
// Moving through the game review tree shouldn't require a full invocatian. This object, and most
|
||||
// other view models, should be exported to the UI.
|
||||
|
||||
use crate::{types::{BFSIter, Node}, Goban, Tree};
|
||||
use crate::{types::SizeNode, DepthTree, Goban};
|
||||
use nary_tree::{NodeId, NodeRef};
|
||||
use sgf::{GameRecord, Player};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use uuid::Uuid;
|
||||
|
||||
struct GameReviewViewModelPrivate {
|
||||
current_position: Option<Uuid>,
|
||||
current_position: Option<NodeId>,
|
||||
game: GameRecord,
|
||||
review_tree: Tree<Uuid>,
|
||||
review_tree: DepthTree,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -40,8 +40,13 @@ pub struct GameReviewViewModel {
|
|||
|
||||
impl GameReviewViewModel {
|
||||
pub fn new(game: GameRecord) -> Self {
|
||||
let review_tree = Tree::from(&game.children[0]);
|
||||
let current_position = game.mainline().last().map(|node| node.id());
|
||||
let (review_tree, current_position) = if !game.trees.is_empty() {
|
||||
let review_tree = DepthTree::from(&game.trees[0]);
|
||||
let current_position = game.mainline().unwrap().last().map(|nr| nr.node_id());
|
||||
(review_tree, current_position)
|
||||
} else {
|
||||
(DepthTree::default(), None)
|
||||
};
|
||||
|
||||
Self {
|
||||
imp: Arc::new(RwLock::new(GameReviewViewModelPrivate {
|
||||
|
@ -62,18 +67,23 @@ impl GameReviewViewModel {
|
|||
|
||||
pub fn game_view(&self) -> Goban {
|
||||
let imp = self.imp.read().unwrap();
|
||||
|
||||
Goban::default().apply_moves(imp.game.mainline()).unwrap()
|
||||
let mainline = imp.game.mainline();
|
||||
match mainline {
|
||||
Some(mainline) => Goban::default()
|
||||
.apply_moves(mainline.map(|nr| nr.data()))
|
||||
.unwrap(),
|
||||
None => Goban::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_tree<F>(&self, f: F)
|
||||
where
|
||||
F: Fn(&Tree<Uuid>, &Node<Uuid>, Option<Uuid>),
|
||||
F: Fn(NodeRef<'_, SizeNode>, Option<NodeId>),
|
||||
{
|
||||
let imp = self.imp.read().unwrap();
|
||||
|
||||
for node in imp.review_tree.bfs_iter() {
|
||||
f(&imp.review_tree, node, imp.current_position);
|
||||
f(node, imp.current_position);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,13 +18,11 @@ use crate::{CoreApi, ResourceManager};
|
|||
use adw::prelude::*;
|
||||
|
||||
use otg_core::{
|
||||
settings::{SettingsRequest, SettingsResponse}, CoreRequest, CoreResponse, GameReviewViewModel
|
||||
settings::{SettingsRequest, SettingsResponse},
|
||||
CoreRequest, CoreResponse, GameReviewViewModel,
|
||||
};
|
||||
use sgf::GameRecord;
|
||||
use std::{
|
||||
rc::Rc,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use crate::views::{GameReview, HomeView, SettingsView};
|
||||
|
||||
|
|
|
@ -37,16 +37,10 @@ You should have received a copy of the GNU General Public License along with On
|
|||
|
||||
use crate::{perftrace, Resource, ResourceManager};
|
||||
|
||||
use gio::resources_lookup_data;
|
||||
use glib::Object;
|
||||
use gtk::{
|
||||
gdk_pixbuf::{Colorspace, InterpType, Pixbuf},
|
||||
prelude::*,
|
||||
subclass::prelude::*,
|
||||
};
|
||||
use image::{io::Reader as ImageReader, ImageError};
|
||||
use gtk::{gdk_pixbuf::Pixbuf, prelude::*, subclass::prelude::*};
|
||||
use otg_core::{Color, Coordinate};
|
||||
use std::{cell::RefCell, io::Cursor, rc::Rc};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
const WIDTH: i32 = 800;
|
||||
const HEIGHT: i32 = 800;
|
||||
|
@ -257,11 +251,11 @@ impl Pen {
|
|||
let (x_loc, y_loc) = self.stone_location(row, col);
|
||||
match color {
|
||||
Color::White => match self.white_stone {
|
||||
Some(ref white_stone) => ctx.set_source_pixbuf(&white_stone, x_loc, y_loc),
|
||||
Some(ref white_stone) => ctx.set_source_pixbuf(white_stone, x_loc, y_loc),
|
||||
None => ctx.set_source_rgb(0.9, 0.9, 0.9),
|
||||
},
|
||||
Color::Black => match self.black_stone {
|
||||
Some(ref black_stone) => ctx.set_source_pixbuf(&black_stone, x_loc, y_loc),
|
||||
Some(ref black_stone) => ctx.set_source_pixbuf(black_stone, x_loc, y_loc),
|
||||
None => ctx.set_source_rgb(0.0, 0.0, 0.0),
|
||||
},
|
||||
}
|
||||
|
@ -309,34 +303,3 @@ impl Pen {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_pixbuf(
|
||||
path: &str,
|
||||
transparency: bool,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<Option<Pixbuf>, ImageError> {
|
||||
let image_bytes = resources_lookup_data(path, gio::ResourceLookupFlags::NONE).unwrap();
|
||||
|
||||
let image = ImageReader::new(Cursor::new(image_bytes))
|
||||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.decode();
|
||||
image.map(|image| {
|
||||
let stride = if transparency {
|
||||
image.to_rgba8().sample_layout().height_stride
|
||||
} else {
|
||||
image.to_rgb8().sample_layout().height_stride
|
||||
};
|
||||
Pixbuf::from_bytes(
|
||||
&glib::Bytes::from(image.as_bytes()),
|
||||
Colorspace::Rgb,
|
||||
transparency,
|
||||
8,
|
||||
image.width() as i32,
|
||||
image.height() as i32,
|
||||
stride as i32,
|
||||
)
|
||||
.scale_simple(width, height, InterpType::Nearest)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -70,14 +70,14 @@ impl ReviewTree {
|
|||
#[allow(deprecated)]
|
||||
let accent_color = context.lookup_color("accent_color").unwrap();
|
||||
|
||||
self.view.map_tree(move |tree, node, current| {
|
||||
let parent = tree.parent(node);
|
||||
self.view.map_tree(move |node, current| {
|
||||
let parent = node.parent();
|
||||
ctx.set_source_rgb(
|
||||
foreground_color.red().into(),
|
||||
foreground_color.green().into(),
|
||||
foreground_color.blue().into(),
|
||||
);
|
||||
let (row, column) = tree.position(node.id);
|
||||
let (row, column) = node.data().position();
|
||||
let y = (row as f64) * SPACING + RADIUS * 2.;
|
||||
let x = (column as f64) * SPACING + RADIUS * 2.;
|
||||
ctx.arc(x, y, RADIUS, 0., 2. * std::f64::consts::PI);
|
||||
|
@ -85,7 +85,7 @@ impl ReviewTree {
|
|||
|
||||
if let Some(parent) = parent {
|
||||
ctx.set_line_width(1.);
|
||||
let (row, column) = tree.position(parent.id);
|
||||
let (row, column) = parent.data().position();
|
||||
let py = (row as f64) * SPACING + RADIUS * 2.;
|
||||
let px = (column as f64) * SPACING + RADIUS * 2.;
|
||||
ctx.move_to(px, py);
|
||||
|
@ -93,7 +93,7 @@ impl ReviewTree {
|
|||
let _ = ctx.stroke();
|
||||
}
|
||||
|
||||
if current == Some(node.content) {
|
||||
if current == Some(node.data().game_node_id) {
|
||||
ctx.set_line_width(HIGHLIGHT_WIDTH);
|
||||
ctx.set_source_rgb(
|
||||
accent_color.red().into(),
|
||||
|
@ -118,138 +118,3 @@ impl ReviewTree {
|
|||
}
|
||||
}
|
||||
|
||||
// https://llimllib.github.io/pymag-trees/
|
||||
// I want to take advantage of the Wetherell Shannon algorithm, but I want some variations. In
|
||||
// their diagram, they got a tree that looks like this.
|
||||
//
|
||||
// O
|
||||
// |\
|
||||
// O O
|
||||
// |\ \ \
|
||||
// O O O O
|
||||
// |\ |\
|
||||
// O O O O
|
||||
//
|
||||
// In the same circumstance, what I want is this:
|
||||
//
|
||||
// O--
|
||||
// | \
|
||||
// O O
|
||||
// |\ |\
|
||||
// O O O O
|
||||
// |\
|
||||
// O O
|
||||
//
|
||||
// In order to keep things from being overly smooshed, I want to ensure that if a branch overlaps
|
||||
// with another branch, there is some extra drawing space. This might actually be similar to adding
|
||||
// the principal that "A parent should be centered over its children".
|
||||
//
|
||||
// So, given a tree, I need to know how many children exist at each level. Then I build parents
|
||||
// atop the children. At level 3, I have four children, and that happens to be the maximum width of
|
||||
// the graph.
|
||||
//
|
||||
// A bottom-up traversal:
|
||||
// - Figure out the number of nodes at each depth
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use sgf::{Color, GameNode, Move, MoveNode};
|
||||
|
||||
#[test]
|
||||
fn it_calculates_width_for_single_node() {
|
||||
let node = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
||||
|
||||
assert_eq!(node_width(&node), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_calculates_width_for_node_with_children() {
|
||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_b = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
||||
let node_c = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
||||
let node_d = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
||||
|
||||
node_a.children.push(node_b);
|
||||
node_a.children.push(node_c);
|
||||
node_a.children.push(node_d);
|
||||
|
||||
assert_eq!(node_width(&GameNode::MoveNode(node_a)), 3);
|
||||
}
|
||||
|
||||
// A
|
||||
// B E
|
||||
// C D
|
||||
#[test]
|
||||
fn it_calculates_width_with_one_deep_child() {
|
||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_b = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_c = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_d = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_e = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
|
||||
node_b.children.push(GameNode::MoveNode(node_c));
|
||||
node_b.children.push(GameNode::MoveNode(node_d));
|
||||
assert_eq!(node_width(&GameNode::MoveNode(node_b.clone())), 2);
|
||||
|
||||
node_a.children.push(GameNode::MoveNode(node_b));
|
||||
node_a.children.push(GameNode::MoveNode(node_e));
|
||||
assert_eq!(node_width(&GameNode::MoveNode(node_a)), 3);
|
||||
}
|
||||
|
||||
// A
|
||||
// B G H
|
||||
// C I
|
||||
// D E F
|
||||
#[test]
|
||||
fn it_calculates_a_complex_tree() {
|
||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_b = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_c = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_d = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_e = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_f = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_g = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let mut node_h = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_i = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
|
||||
node_c.children.push(GameNode::MoveNode(node_d));
|
||||
node_c.children.push(GameNode::MoveNode(node_e));
|
||||
node_c.children.push(GameNode::MoveNode(node_f));
|
||||
assert_eq!(node_width(&GameNode::MoveNode(node_c.clone())), 3);
|
||||
|
||||
node_b.children.push(GameNode::MoveNode(node_c));
|
||||
assert_eq!(node_width(&GameNode::MoveNode(node_b.clone())), 3);
|
||||
|
||||
node_h.children.push(GameNode::MoveNode(node_i));
|
||||
|
||||
node_a.children.push(GameNode::MoveNode(node_b));
|
||||
node_a.children.push(GameNode::MoveNode(node_g));
|
||||
node_a.children.push(GameNode::MoveNode(node_h));
|
||||
// This should be 4 if I were collapsing levels correctly, but it is 5 until I return to
|
||||
// figure that step out.
|
||||
assert_eq!(node_width(&GameNode::MoveNode(node_a.clone())), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_nodes_children_get_separate_columns() {
|
||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
||||
let node_b = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
||||
let node_c = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
||||
let node_d = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
||||
|
||||
node_a.children.push(node_b.clone());
|
||||
node_a.children.push(node_c.clone());
|
||||
node_a.children.push(node_d.clone());
|
||||
|
||||
assert_eq!(
|
||||
node_children_columns(&GameNode::MoveNode(node_a)),
|
||||
vec![0, 1, 2]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_renderer() {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ pub struct ResourceManager {
|
|||
resources: Rc<RefCell<HashMap<String, Resource>>>,
|
||||
}
|
||||
|
||||
impl ResourceManager {
|
||||
pub fn new() -> Self {
|
||||
impl Default for ResourceManager {
|
||||
fn default() -> Self {
|
||||
let mut resources = HashMap::new();
|
||||
|
||||
for (path, xres, yres, transparency) in [
|
||||
|
@ -88,7 +88,9 @@ impl ResourceManager {
|
|||
resources: Rc::new(RefCell::new(resources)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceManager {
|
||||
pub fn resource(&self, path: &str) -> Option<Resource> {
|
||||
self.resources.borrow().get(path).cloned()
|
||||
}
|
||||
|
@ -123,7 +125,6 @@ impl ResourceManager {
|
|||
.scale_simple(width, height, InterpType::Nearest)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn perftrace<F, A>(trace_name: &str, f: F) -> A
|
||||
|
|
|
@ -122,7 +122,7 @@ fn main() {
|
|||
|
||||
app.connect_activate({
|
||||
move |app| {
|
||||
let resources = ResourceManager::new();
|
||||
let resources = ResourceManager::default();
|
||||
let core_api = CoreApi { core: core.clone() };
|
||||
let app_window = AppWindow::new(app, core_api, resources);
|
||||
|
||||
|
|
|
@ -22,15 +22,9 @@ You should have received a copy of the GNU General Public License along with On
|
|||
// I'll get all of the information about the game from the core, and then render everything in the
|
||||
// UI. So this will be a heavy lift on the UI side.
|
||||
|
||||
use crate::{
|
||||
components::{Goban, PlayerCard, ReviewTree},
|
||||
CoreApi, ResourceManager,
|
||||
};
|
||||
use glib::Object;
|
||||
use gtk::{prelude::*, subclass::prelude::*};
|
||||
use crate::{components::{Goban, PlayerCard, ReviewTree}, ResourceManager};
|
||||
use gtk::{prelude::*};
|
||||
use otg_core::{Color, GameReviewViewModel};
|
||||
use sgf::GameRecord;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
/*
|
||||
#[derive(Default)]
|
||||
|
@ -89,11 +83,6 @@ impl GameReview {
|
|||
// It's actually really bad to be just throwing away errors. Panics make everyone unhappy.
|
||||
// This is not a fatal error, so I'll replace this `unwrap` call with something that
|
||||
// renders the board and notifies the user of a problem that cannot be resolved.
|
||||
/*
|
||||
let board_repr = otg_core::Goban::default()
|
||||
.apply_moves(record.mainline())
|
||||
.unwrap();
|
||||
*/
|
||||
let board_repr = self.view.game_view();
|
||||
let board = Goban::new(board_repr, self.resources.clone());
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ edition = "2021"
|
|||
chrono = { version = "0.4", features = [ "serde" ] }
|
||||
nom = { version = "7" }
|
||||
serde = { version = "1", features = [ "derive" ] }
|
||||
nary_tree = { version = "0.4" }
|
||||
thiserror = { version = "1"}
|
||||
typeshare = { version = "1" }
|
||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||
|
|
448
sgf/src/game.rs
448
sgf/src/game.rs
|
@ -2,8 +2,15 @@ use crate::{
|
|||
parser::{self, Annotation, Evaluation, Move, SetupInstr, Size, UnknownProperty},
|
||||
Color, Date, GameResult, GameType,
|
||||
};
|
||||
use nary_tree::{NodeId, NodeMut, NodeRef, Tree};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
fmt,
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
time::Duration,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -32,7 +39,7 @@ pub enum SetupNodeError {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum GameNodeError {
|
||||
UnsupportedGameNode(MoveNodeError, SetupNodeError),
|
||||
UnsupportedGameNode(MoveNodeError, SetupNodeError, parser::Node),
|
||||
ConflictingProperty,
|
||||
ConflictingPosition,
|
||||
}
|
||||
|
@ -52,7 +59,7 @@ pub struct Player {
|
|||
/// syntax issues, the result of the GameRecord is to have a fully-understood game. However, this
|
||||
/// doesn't (yet?) go quite to the level of apply the game type (i.e., this is Go, Chess, Yinsh, or
|
||||
/// whatever).
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct GameRecord {
|
||||
pub game_type: GameType,
|
||||
|
||||
|
@ -78,7 +85,7 @@ pub struct GameRecord {
|
|||
pub overtime: Option<String>,
|
||||
pub transcriber: Option<String>,
|
||||
|
||||
pub children: Vec<GameNode>,
|
||||
pub trees: Vec<GameTree>,
|
||||
}
|
||||
|
||||
impl GameRecord {
|
||||
|
@ -111,55 +118,40 @@ impl GameRecord {
|
|||
overtime: None,
|
||||
transcriber: None,
|
||||
|
||||
children: vec![],
|
||||
trees: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nodes(&self) -> Vec<&GameNode> {
|
||||
self.iter().collect()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &'_ GameNode> {
|
||||
self.trees
|
||||
.iter()
|
||||
.flat_map(|tree| tree.root().unwrap().traverse_pre_order())
|
||||
.map(|nr| nr.data())
|
||||
}
|
||||
|
||||
/// Generate a list of moves which constitute the main line of the game. This is the game as it
|
||||
/// was actually played out, and by convention consists of the first node in each list of
|
||||
/// children.
|
||||
pub fn mainline(&self) -> Vec<&GameNode> {
|
||||
let mut moves: Vec<&GameNode> = vec![];
|
||||
|
||||
let mut next = self.children.first();
|
||||
while let Some(node) = next {
|
||||
// Given that I know that I have a node, and I know that I'm going to push a reference
|
||||
// to it onto my final list, I want to get the first of its children. And I want to
|
||||
// keep doing that until there are no more first children.
|
||||
//
|
||||
// Just going to push references onto the list. No need to copy the nodes for this.
|
||||
//
|
||||
// Pushing a reference onto the list implicitely clones the reference, but not the data
|
||||
// it is pointing to. This means that each time through the loop, `next` points to
|
||||
// something else. This isn't being described very well, though, so it's worth
|
||||
// reviewing in the future.
|
||||
moves.push(node);
|
||||
|
||||
next = match node {
|
||||
GameNode::MoveNode(node) => node.children.first(),
|
||||
GameNode::SetupNode(node) => node.children.first(),
|
||||
};
|
||||
pub fn mainline(&self) -> Option<impl Iterator<Item = NodeRef<'_, GameNode>>> {
|
||||
if !self.trees.is_empty() {
|
||||
Some(MainlineIter {
|
||||
next: self.trees[0].root(),
|
||||
tree: &self.trees[0],
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
moves
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for GameRecord {
|
||||
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
|
||||
self.children.iter().collect::<Vec<&'a GameNode>>()
|
||||
}
|
||||
|
||||
fn add_child(&mut self, node: GameNode) -> &mut GameNode {
|
||||
self.children.push(node);
|
||||
self.children.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&parser::Tree> for GameRecord {
|
||||
impl TryFrom<parser::Tree> for GameRecord {
|
||||
type Error = GameError;
|
||||
|
||||
fn try_from(tree: &parser::Tree) -> Result<Self, Self::Error> {
|
||||
fn try_from(tree: parser::Tree) -> Result<Self, Self::Error> {
|
||||
let mut ty = None;
|
||||
let mut size = None;
|
||||
let mut black_player = Player {
|
||||
|
@ -234,6 +226,7 @@ impl TryFrom<&parser::Tree> for GameRecord {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
s.children = tree
|
||||
.root
|
||||
.next
|
||||
|
@ -241,33 +234,205 @@ impl TryFrom<&parser::Tree> for GameRecord {
|
|||
.map(GameNode::try_from)
|
||||
.collect::<Result<Vec<GameNode>, GameNodeError>>()
|
||||
.map_err(GameError::InvalidGameNode)?;
|
||||
*/
|
||||
|
||||
s.trees = tree
|
||||
.root
|
||||
.next
|
||||
.into_iter()
|
||||
.map(recursive_tree_to_slab_tree)
|
||||
.collect::<Result<Vec<GameTree>, GameError>>()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
fn recursive_tree_to_slab_tree(node: parser::Node) -> Result<GameTree, GameError> {
|
||||
let mut slab = Tree::new();
|
||||
let mut nodes: VecDeque<(NodeId, parser::Node)> = VecDeque::new();
|
||||
|
||||
let root_id =
|
||||
slab.set_root(GameNode::try_from(node.clone()).map_err(GameError::InvalidGameNode)?);
|
||||
nodes.push_back((root_id, node));
|
||||
|
||||
// I need to keep track of the current parent, and I need to keep on digging deeper into the
|
||||
// tree. Given that I have the root, I can then easily find out all of the children.
|
||||
//
|
||||
// So, maybe I take the list of children. Assign each one of them to a place in the slab tree.
|
||||
// Then push the child *and* its ID into a dequeue. So long as the dequeue is not empty, I want
|
||||
// to pop a node and its ID from the dequeue. The retrieve the NodeMut for it and work on the
|
||||
// node's children.
|
||||
while let Some((node_id, node)) = nodes.pop_front() {
|
||||
let mut game_node: NodeMut<GameNode> = slab
|
||||
.get_mut(node_id)
|
||||
.expect("invalid node_id when retrieving nodes from the game");
|
||||
// I have a node that is in the tree. Now run across all of its children, adding each one
|
||||
// to the tree and pushing them into the deque along with their IDs.
|
||||
for child in node.next {
|
||||
let slab_child = game_node
|
||||
.append(GameNode::try_from(child.clone()).map_err(GameError::InvalidGameNode)?);
|
||||
nodes.push_back((slab_child.node_id(), child));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(GameTree(slab))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TreeIter<'a> {
|
||||
queue: VecDeque<NodeRef<'a, &'a GameNode>>,
|
||||
}
|
||||
|
||||
/*
|
||||
impl<'a> Default for TreeIter<'a> {
|
||||
fn default() -> Self {
|
||||
TreeIter {
|
||||
queue: VecDeque::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<'a> Iterator for TreeIter<'a> {
|
||||
type Item = &'a GameNode;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let retval = self.queue.pop_front();
|
||||
if let Some(ref retval) = retval {
|
||||
retval
|
||||
.children()
|
||||
.for_each(|node| self.queue.push_back(node));
|
||||
}
|
||||
retval.map(|rv| *rv.data())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GameTree(Tree<GameNode>);
|
||||
|
||||
impl Default for GameTree {
|
||||
fn default() -> Self {
|
||||
Self(Tree::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for GameTree {
|
||||
fn clone(&self) -> Self {
|
||||
match self.0.root() {
|
||||
None => Self(Tree::new()),
|
||||
Some(source_root_node) => {
|
||||
let mut dest = Tree::new();
|
||||
let dest_root_id = dest.set_root(source_root_node.data().clone());
|
||||
|
||||
// In order to add a node to the new tree, I need to know the ID of the parent in
|
||||
// the source tree and the ID of the parent in the destination tree. So I want a
|
||||
// lookup table that maps source IDs to destination IDs. But is that sufficient?
|
||||
// Perhaps I can just keep a mapping from a source noderef to a destination ID.
|
||||
// I don't think I can keep more than one mutable destination node.
|
||||
|
||||
let mut mapping: HashMap<NodeId, NodeId> = HashMap::new();
|
||||
mapping.insert(source_root_node.node_id(), dest_root_id);
|
||||
|
||||
for source_node in source_root_node.traverse_level_order() {
|
||||
match source_node.parent() {
|
||||
None => {}
|
||||
Some(parent) => {
|
||||
let source_node_parent_id = parent.node_id();
|
||||
let target_node_parent_id = mapping.get(&source_node_parent_id).expect("node should have been added to the source to dest mapping when being cloned");
|
||||
|
||||
let mut parent = dest.get_mut(*target_node_parent_id).expect(
|
||||
"destination parent node to exist before reaching potential children",
|
||||
);
|
||||
let dest_id = parent.append(source_node.data().clone()).node_id();
|
||||
mapping.insert(source_node.node_id(), dest_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self(dest)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for GameTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
self.write_formatted(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for GameTree {
|
||||
type Target = Tree<GameNode>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for GameTree {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for GameTree {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// Get pre-order iterators over both trees, zip them, and ensure that the data contents are
|
||||
// the same between them
|
||||
let left_root = self.root();
|
||||
let right_root = other.root();
|
||||
|
||||
match (left_root, right_root) {
|
||||
(Some(left_root), Some(right_root)) => {
|
||||
for (left_node, right_node) in std::iter::zip(
|
||||
left_root.traverse_pre_order(),
|
||||
right_root.traverse_pre_order(),
|
||||
) {
|
||||
if left_node.data() != right_node.data() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, None) => return true,
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MainlineIter<'a> {
|
||||
next: Option<NodeRef<'a, GameNode>>,
|
||||
tree: &'a Tree<GameNode>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for MainlineIter<'a> {
|
||||
type Item = NodeRef<'a, GameNode>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(next) = self.next.take() {
|
||||
let ret = self.tree.get(next.node_id())?;
|
||||
self.next = next
|
||||
.first_child()
|
||||
.and_then(|child| self.tree.get(child.node_id()));
|
||||
Some(ret)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
pub enum GameNode {
|
||||
MoveNode(MoveNode),
|
||||
SetupNode(SetupNode),
|
||||
}
|
||||
|
||||
pub trait Node {
|
||||
/// Provide a pre-order traversal of all of the nodes in the game tree.
|
||||
fn nodes<'a>(&'a self) -> Vec<&'a GameNode> {
|
||||
self.children()
|
||||
.iter()
|
||||
.flat_map(|node| {
|
||||
let mut children = node.nodes();
|
||||
let mut v = vec![*node];
|
||||
v.append(&mut children);
|
||||
v
|
||||
})
|
||||
.collect::<Vec<&'a GameNode>>()
|
||||
impl fmt::Display for GameNode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
GameNode::MoveNode(_) => write!(f, "MoveNode"),
|
||||
GameNode::SetupNode(_) => write!(f, "SetupNode"),
|
||||
}
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<&GameNode>;
|
||||
fn add_child(&mut self, node: GameNode) -> &mut GameNode;
|
||||
}
|
||||
|
||||
impl GameNode {
|
||||
|
@ -279,70 +444,20 @@ impl GameNode {
|
|||
}
|
||||
}
|
||||
|
||||
impl Node for GameNode {
|
||||
fn children(&self) -> Vec<&GameNode> {
|
||||
match self {
|
||||
GameNode::MoveNode(node) => node.children(),
|
||||
GameNode::SetupNode(node) => node.children(),
|
||||
}
|
||||
}
|
||||
|
||||
fn nodes(&self) -> Vec<&GameNode> {
|
||||
match self {
|
||||
GameNode::MoveNode(node) => node.nodes(),
|
||||
GameNode::SetupNode(node) => node.nodes(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_child(&mut self, new_node: GameNode) -> &mut GameNode {
|
||||
match self {
|
||||
GameNode::MoveNode(node) => node.add_child(new_node),
|
||||
GameNode::SetupNode(node) => node.add_child(new_node),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&parser::Node> for GameNode {
|
||||
impl TryFrom<parser::Node> for GameNode {
|
||||
type Error = GameNodeError;
|
||||
|
||||
fn try_from(n: &parser::Node) -> Result<Self, Self::Error> {
|
||||
// I originally wrote this recursively. However, on an ordinary game of a couple hundred
|
||||
// moves, that meant that I was recursing 500 functions, and that exceeded the stack limit.
|
||||
// So, instead, I need to unroll everything to non-recursive form.
|
||||
//
|
||||
// So, I can treat each branch of the tree as a single line. Iterate over that line. I can
|
||||
// only use the MoveNode::try_from and SetupNode::try_from if those functions don't
|
||||
// recurse. Instead, I'm going to process just that node, then return to here and process
|
||||
// the children.
|
||||
let move_node = MoveNode::try_from(n);
|
||||
let setup_node = SetupNode::try_from(n);
|
||||
fn try_from(n: parser::Node) -> Result<Self, Self::Error> {
|
||||
let move_node = MoveNode::try_from(n.clone());
|
||||
let setup_node = SetupNode::try_from(n.clone());
|
||||
|
||||
// I'm much too tired when writing this. I'm still recursing, but I did cut the number of
|
||||
// recursions in half. This helps, but it still doesn't guarantee that I'm going to be able
|
||||
// to parse all possible games. So, still, treat each branch of the game as a single line.
|
||||
// Iterate over that line, don't recurse. Create bookmarks at each branch point, and then
|
||||
// come back to each one.
|
||||
let children = n
|
||||
.next
|
||||
.iter()
|
||||
.map(GameNode::try_from)
|
||||
.collect::<Result<Vec<Self>, Self::Error>>()?;
|
||||
|
||||
let node = match (move_node, setup_node) {
|
||||
(Ok(mut node), _) => {
|
||||
node.children = children;
|
||||
Ok(Self::MoveNode(node))
|
||||
}
|
||||
(Err(_), Ok(mut node)) => {
|
||||
node.children = children;
|
||||
Ok(Self::SetupNode(node))
|
||||
}
|
||||
match (move_node, setup_node) {
|
||||
(Ok(node), _) => Ok(Self::MoveNode(node)),
|
||||
(Err(_), Ok(node)) => Ok(Self::SetupNode(node)),
|
||||
(Err(move_err), Err(setup_err)) => {
|
||||
Err(Self::Error::UnsupportedGameNode(move_err, setup_err))
|
||||
Err(Self::Error::UnsupportedGameNode(move_err, setup_err, n))
|
||||
}
|
||||
}?;
|
||||
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,7 +466,6 @@ pub struct MoveNode {
|
|||
pub id: Uuid,
|
||||
pub color: Color,
|
||||
pub mv: Move,
|
||||
pub children: Vec<GameNode>,
|
||||
|
||||
pub time_left: Option<Duration>,
|
||||
pub moves_left: Option<usize>,
|
||||
|
@ -369,7 +483,6 @@ impl MoveNode {
|
|||
id: Uuid::new_v4(),
|
||||
color,
|
||||
mv,
|
||||
children: Vec::new(),
|
||||
|
||||
time_left: None,
|
||||
moves_left: None,
|
||||
|
@ -383,21 +496,10 @@ impl MoveNode {
|
|||
}
|
||||
}
|
||||
|
||||
impl Node for MoveNode {
|
||||
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
|
||||
self.children.iter().collect::<Vec<&'a GameNode>>()
|
||||
}
|
||||
|
||||
fn add_child(&mut self, node: GameNode) -> &mut GameNode {
|
||||
self.children.push(node);
|
||||
self.children.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&parser::Node> for MoveNode {
|
||||
impl TryFrom<parser::Node> for MoveNode {
|
||||
type Error = MoveNodeError;
|
||||
|
||||
fn try_from(n: &parser::Node) -> Result<Self, Self::Error> {
|
||||
fn try_from(n: parser::Node) -> Result<Self, Self::Error> {
|
||||
let s = match n.mv() {
|
||||
Some((color, mv)) => {
|
||||
let mut s = Self::new(color, mv);
|
||||
|
@ -460,7 +562,6 @@ pub struct SetupNode {
|
|||
id: Uuid,
|
||||
|
||||
pub positions: Vec<parser::SetupInstr>,
|
||||
pub children: Vec<GameNode>,
|
||||
}
|
||||
|
||||
impl SetupNode {
|
||||
|
@ -480,26 +581,14 @@ impl SetupNode {
|
|||
Ok(Self {
|
||||
id: Uuid::new_v4(),
|
||||
positions,
|
||||
children: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for SetupNode {
|
||||
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
|
||||
self.children.iter().collect::<Vec<&'a GameNode>>()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn add_child(&mut self, _node: GameNode) -> &mut GameNode {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&parser::Node> for SetupNode {
|
||||
impl TryFrom<parser::Node> for SetupNode {
|
||||
type Error = SetupNodeError;
|
||||
|
||||
fn try_from(n: &parser::Node) -> Result<Self, Self::Error> {
|
||||
fn try_from(n: parser::Node) -> Result<Self, Self::Error> {
|
||||
match n.setup() {
|
||||
Some(elements) => Self::new(elements),
|
||||
None => Err(Self::Error::NotASetupNode),
|
||||
|
@ -507,6 +596,7 @@ impl TryFrom<&parser::Node> for SetupNode {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[allow(dead_code)]
|
||||
pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> {
|
||||
if node.id() == id {
|
||||
|
@ -523,6 +613,7 @@ pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> {
|
|||
|
||||
Vec::new()
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
@ -543,6 +634,7 @@ mod test {
|
|||
assert_eq!(tree.nodes().len(), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
fn it_can_add_moves_to_a_game() {
|
||||
let mut game = GameRecord::new(
|
||||
|
@ -555,16 +647,21 @@ mod test {
|
|||
Player::default(),
|
||||
);
|
||||
|
||||
/*
|
||||
let first_move = MoveNode::new(Color::Black, Move::Move("dd".to_owned()));
|
||||
let first_ = game.add_child(GameNode::MoveNode(first_move.clone()));
|
||||
let second_move = MoveNode::new(Color::White, Move::Move("qq".to_owned()));
|
||||
first_.add_child(GameNode::MoveNode(second_move.clone()));
|
||||
*/
|
||||
|
||||
/*
|
||||
let nodes = game.nodes();
|
||||
assert_eq!(nodes.len(), 2);
|
||||
assert_eq!(nodes[0].id(), first_move.id);
|
||||
assert_eq!(nodes[1].id(), second_move.id);
|
||||
*/
|
||||
}
|
||||
*/
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
|
@ -588,7 +685,7 @@ mod test {
|
|||
],
|
||||
next: vec![],
|
||||
};
|
||||
assert_matches!(GameNode::try_from(&n), Ok(GameNode::MoveNode(_)));
|
||||
assert_matches!(GameNode::try_from(n), Ok(GameNode::MoveNode(_)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -630,10 +727,10 @@ mod move_node_tests {
|
|||
],
|
||||
next: vec![],
|
||||
};
|
||||
assert_matches!(MoveNode::try_from(&n), Ok(node) => {
|
||||
assert_matches!(MoveNode::try_from(n), Ok(node) => {
|
||||
assert_eq!(node.color, Color::White);
|
||||
assert_eq!(node.mv, Move::Move("dp".to_owned()));
|
||||
assert_eq!(node.children, vec![]);
|
||||
// assert_eq!(node.children, vec![]);
|
||||
assert_eq!(node.time_left, Some(Duration::from_secs(176)));
|
||||
assert_eq!(node.comments, Some("Comments in the game".to_owned()));
|
||||
});
|
||||
|
@ -653,7 +750,7 @@ mod move_node_tests {
|
|||
next: vec![],
|
||||
};
|
||||
assert_matches!(
|
||||
MoveNode::try_from(&n),
|
||||
MoveNode::try_from(n),
|
||||
Err(MoveNodeError::IncompatibleProperty(_))
|
||||
);
|
||||
}
|
||||
|
@ -703,7 +800,7 @@ mod path_test {
|
|||
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(text).unwrap();
|
||||
let games = games
|
||||
.into_iter()
|
||||
.map(|game| GameRecord::try_from(&game).expect("game to parse"))
|
||||
.map(|game| GameRecord::try_from(game).expect("game to parse"))
|
||||
.collect::<Vec<GameRecord>>();
|
||||
f(games);
|
||||
}
|
||||
|
@ -722,7 +819,11 @@ mod path_test {
|
|||
|games| {
|
||||
let game = &games[0];
|
||||
|
||||
let moves = game.mainline();
|
||||
let moves = game
|
||||
.mainline()
|
||||
.expect("there should be a mainline in this file")
|
||||
.map(|nr| nr.data())
|
||||
.collect::<Vec<&GameNode>>();
|
||||
assert_matches!(moves[0], GameNode::MoveNode(node) => {
|
||||
assert_eq!(node.color, Color::Black);
|
||||
assert_eq!(node.mv, Move::Move("pp".to_owned()));
|
||||
|
@ -744,7 +845,11 @@ mod path_test {
|
|||
with_file(std::path::Path::new("test_data/branch_test.sgf"), |games| {
|
||||
let game = &games[0];
|
||||
|
||||
let moves = game.mainline();
|
||||
let moves = game
|
||||
.mainline()
|
||||
.expect("there should be a mainline in this file")
|
||||
.map(|nr| nr.data())
|
||||
.collect::<Vec<&GameNode>>();
|
||||
assert_matches!(moves[1], GameNode::MoveNode(node) => {
|
||||
assert_eq!(node.color, Color::White);
|
||||
assert_eq!(node.mv, Move::Move("dd".to_owned()));
|
||||
|
@ -791,7 +896,7 @@ mod file_test {
|
|||
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(text).unwrap();
|
||||
let games = games
|
||||
.into_iter()
|
||||
.map(|game| GameRecord::try_from(&game).expect("game to parse"))
|
||||
.map(|game| GameRecord::try_from(game).expect("game to parse"))
|
||||
.collect::<Vec<GameRecord>>();
|
||||
f(games);
|
||||
}
|
||||
|
@ -875,6 +980,7 @@ mod file_test {
|
|||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
let children = game.children();
|
||||
let node = children.first().unwrap();
|
||||
assert_matches!(node, GameNode::MoveNode(node) => {
|
||||
|
@ -892,6 +998,7 @@ mod file_test {
|
|||
assert_eq!(node.time_left, Some(Duration::from_secs(1765)));
|
||||
assert_eq!(node.comments, None);
|
||||
});
|
||||
*/
|
||||
/*
|
||||
let node = node.next().unwrap();
|
||||
let expected_properties = vec![
|
||||
|
@ -911,4 +1018,39 @@ mod file_test {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_load_a_file_with_multiple_roots() {
|
||||
with_file(std::path::Path::new("test_data/multi-tree.sgf"), |games| {
|
||||
assert_eq!(games.len(), 1);
|
||||
let game = &games[0];
|
||||
assert_eq!(game.game_type, GameType::Go);
|
||||
assert_eq!(
|
||||
game.board_size,
|
||||
Size {
|
||||
width: 19,
|
||||
height: 19
|
||||
}
|
||||
);
|
||||
assert_eq!(game.trees.len(), 2);
|
||||
assert_matches!(game.trees[0].root().unwrap().data(), GameNode::MoveNode(node) => {
|
||||
assert_eq!(node.color, Color::Black);
|
||||
assert_eq!(node.mv, Move::Move("pd".to_owned()));
|
||||
});
|
||||
assert_matches!(game.trees[1].root().unwrap().data(), GameNode::MoveNode(node) => {
|
||||
assert_eq!(node.color, Color::Black);
|
||||
assert_eq!(node.mv, Move::Move("pc".to_owned()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_copy_a_game_record() {
|
||||
with_file(std::path::Path::new("test_data/multi-tree.sgf"), |games| {
|
||||
let dest = games.clone();
|
||||
|
||||
assert_eq!(games.len(), dest.len());
|
||||
assert_eq!(games[0], dest[0]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod date;
|
||||
|
||||
mod game;
|
||||
pub use game::{GameNode, GameRecord, MoveNode, Player};
|
||||
pub use game::{GameNode, GameRecord, GameTree, MoveNode, Player};
|
||||
|
||||
mod parser;
|
||||
pub use parser::{parse_collection, Move};
|
||||
|
@ -22,6 +22,7 @@ pub enum Error {
|
|||
InvalidSgf(VerboseNomError),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct VerboseNomError(nom::error::VerboseError<String>);
|
||||
|
||||
|
@ -73,7 +74,7 @@ pub fn parse_sgf(input: &str) -> Result<Vec<Result<GameRecord, game::GameError>>
|
|||
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(input)?;
|
||||
let games = games
|
||||
.into_iter()
|
||||
.map(|game| GameRecord::try_from(&game))
|
||||
.map(GameRecord::try_from)
|
||||
.collect::<Vec<Result<GameRecord, game::GameError>>>();
|
||||
|
||||
Ok(games)
|
||||
|
|
|
@ -56,6 +56,7 @@ pub enum Error {
|
|||
InvalidSgf(VerboseNomError),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct VerboseNomError(nom::error::VerboseError<String>);
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[7.5]SZ[19]DT[2024-04-19](;B[pd](;W[qc];B[qd];W[pc];B[oc];W[ob];B[nc];W[nb];B[mc];W[rd];B[re];W[rc];B[qf])(;W[qf];B[nc];W[rd];B[qc];W[pi]))(;B[pc];W[qe];B[oe];W[pg];B[ld];W[qj]))
|
|
@ -9,6 +9,10 @@ use std::{
|
|||
rc::Rc,
|
||||
};
|
||||
|
||||
// I need to take what I learned about linked lists and about the other Tree data structure, and
|
||||
// apply it here with arena allocation.
|
||||
//
|
||||
// Also, smarter node allocation and pointer handling in order to avoid clones.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub enum Tree<T> {
|
||||
#[default]
|
||||
|
@ -55,6 +59,16 @@ impl<T> Tree<T> {
|
|||
None
|
||||
}
|
||||
|
||||
// Do a depth-first-search in order to get the path to a node. Start with a naive recursive
|
||||
// implementation, then switch to a stack-based implementation in order to avoid exceeding the
|
||||
// stack.
|
||||
pub fn path_to<F>(&self, f: F) -> Vec<Node<T>>
|
||||
where
|
||||
F: FnOnce(&T) -> bool + Copy,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Convert each node of a tree from type T to type U
|
||||
pub fn map<F, U>(&self, op: F) -> Tree<U>
|
||||
where
|
||||
|
@ -146,6 +160,13 @@ impl<T> Node<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for Node<T> {
|
||||
fn eq(&self, other: &Node<T>) -> bool {
|
||||
self.0.borrow().value == other.0.borrow().value
|
||||
&& self.0.borrow().children == other.0.borrow().children
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -184,4 +205,31 @@ mod tests {
|
|||
assert!(tree2.find_bfs(|val| *val == "16").is_some());
|
||||
assert!(tree2.find_bfs(|val| *val == "17").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_to_on_empty_tree_returns_empty() {
|
||||
let tree: Tree<&str> = Tree::default();
|
||||
|
||||
assert_eq!(tree.path_to(|val| *val == "i"), vec![]);
|
||||
}
|
||||
|
||||
// A
|
||||
// B G H
|
||||
// C I
|
||||
// D E F
|
||||
#[test]
|
||||
fn it_can_find_a_path_to_a_node() {
|
||||
let (tree, a) = Tree::new("A");
|
||||
let b = a.add_child_value("B");
|
||||
let c = b.add_child_value("C");
|
||||
let _d = c.add_child_value("D");
|
||||
let _e = c.add_child_value("D");
|
||||
let _f = c.add_child_value("D");
|
||||
let _g = a.add_child_value("G");
|
||||
let h = a.add_child_value("H");
|
||||
let i = a.add_child_value("I");
|
||||
|
||||
assert_eq!(tree.path_to(|val| *val == "z"), vec![]);
|
||||
assert_eq!(tree.path_to(|val| *val == "i"), vec![a, h, i]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue