Updated everything and moved to hard tab indentation
This commit is contained in:
1 parent
7cdfe7e3c4
commit
52c8d1c95a
100 files changed
+5949
-5998
No files matched your search
+1
-1
@@ -8,7 +8,7 @@ root = true
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
|
||||
Generated
+179
-247
@@ -28,15 +28,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
@@ -49,33 +49,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.5"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.4"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
@@ -83,15 +83,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
@@ -116,9 +116,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "1.5.1"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed"
|
||||
checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03"
|
||||
dependencies = [
|
||||
"borsh-derive",
|
||||
"cfg_aliases",
|
||||
@@ -126,16 +126,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "borsh-derive"
|
||||
version = "1.5.1"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b"
|
||||
checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
"syn_derive",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -155,22 +154,28 @@ version = "0.6.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.6.1"
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.7"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
|
||||
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -186,9 +191,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.4"
|
||||
version = "4.5.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||
checksum = "9560b07a799281c7e0958b9296854d6fafd4c5f31444a7e5bb1ad6dde5ccf1bd"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -196,51 +201,51 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.2"
|
||||
version = "4.5.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||
checksum = "874e0dd3eb68bf99058751ac9712f622e61e6f393a94f7128fa26e3f02f5c7cd"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim 0.11.1",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.4"
|
||||
version = "4.5.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.2"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "const_panic"
|
||||
version = "0.2.8"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b"
|
||||
checksum = "53857514f72ee4a2b583de67401e3ff63a5472ca4acf289d09a9ea7636dfec17"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.12"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -257,9 +262,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.8"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
|
||||
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -267,27 +272,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.8"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
|
||||
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"strsim 0.10.0",
|
||||
"syn 2.0.52",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"strsim",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.8"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
||||
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -319,9 +324,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.10.0"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
@@ -359,9 +364,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.14"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -377,12 +382,6 @@ dependencies = [
|
||||
"ahash 0.7.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
@@ -408,12 +407,12 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.5",
|
||||
"hashbrown 0.15.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -422,15 +421,6 @@ version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
@@ -442,15 +432,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "konst"
|
||||
version = "0.3.9"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50a0ba6de5f7af397afff922f22c149ff605c766cd3269cf6c1cd5e466dbe3b9"
|
||||
checksum = "4381b9b00c55f251f2ebe9473aef7c117e96828def1a7cb3bd3f0f903c6894e9"
|
||||
dependencies = [
|
||||
"const_panic",
|
||||
"konst_kernel",
|
||||
@@ -460,18 +450,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "konst_kernel"
|
||||
version = "0.3.9"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be0a455a1719220fd6adf756088e1c69a85bf14b6a9e24537a5cc04f503edb2b"
|
||||
checksum = "e4b1eb7788f3824c629b1116a7a9060d6e898c358ebff59070093d51103dcc3c"
|
||||
dependencies = [
|
||||
"typewit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "konst_proc_macros"
|
||||
version = "0.3.0"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e28ab1dc35e09d60c2b8c90d12a9a8d9666c876c10a3739a3196db0103b6043"
|
||||
checksum = "00af7901ba50898c9e545c24d5c580c96a982298134e8037d8978b6594782c07"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
@@ -481,9 +471,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
@@ -508,9 +498,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "orchid-api"
|
||||
@@ -526,18 +516,18 @@ name = "orchid-api-derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"itertools 0.13.0",
|
||||
"itertools",
|
||||
"orchid-api-traits",
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orchid-api-traits"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"itertools",
|
||||
"never",
|
||||
"ordered-float",
|
||||
]
|
||||
@@ -549,7 +539,7 @@ dependencies = [
|
||||
"derive_destructure",
|
||||
"dyn-clone",
|
||||
"hashbrown 0.15.2",
|
||||
"itertools 0.14.0",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"never",
|
||||
"num-traits",
|
||||
@@ -571,7 +561,7 @@ dependencies = [
|
||||
"derive_destructure",
|
||||
"dyn-clone",
|
||||
"hashbrown 0.15.2",
|
||||
"itertools 0.14.0",
|
||||
"itertools",
|
||||
"konst",
|
||||
"lazy_static",
|
||||
"never",
|
||||
@@ -592,7 +582,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"derive_destructure",
|
||||
"hashbrown 0.15.2",
|
||||
"itertools 0.14.0",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"never",
|
||||
"num-traits",
|
||||
@@ -609,7 +599,7 @@ dependencies = [
|
||||
name = "orchid-std"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"itertools",
|
||||
"never",
|
||||
"once_cell",
|
||||
"orchid-api",
|
||||
@@ -626,16 +616,16 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"clap",
|
||||
"itertools 0.13.0",
|
||||
"itertools",
|
||||
"orchid-base",
|
||||
"orchid-host",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "4.2.1"
|
||||
version = "4.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ff2cf528c6c03d9ed653d6c4ce1dc0582dc4af309790ad92f07c1cd551b0be"
|
||||
checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
@@ -648,42 +638,22 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.1.0"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
|
||||
checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
@@ -695,9 +665,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.78"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -717,8 +687,8 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@@ -733,11 +703,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"proc-macro2 1.0.92",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -787,9 +757,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.7.44"
|
||||
version = "0.7.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0"
|
||||
checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"bytecheck",
|
||||
@@ -805,20 +775,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.7.44"
|
||||
version = "0.7.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65"
|
||||
checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.3.0"
|
||||
version = "8.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745"
|
||||
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
@@ -827,22 +797,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.3.0"
|
||||
version = "8.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8"
|
||||
checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"rust-embed-utils",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.95",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.3.0"
|
||||
version = "8.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581"
|
||||
checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"walkdir",
|
||||
@@ -850,9 +820,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.35.0"
|
||||
version = "1.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a"
|
||||
checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"borsh",
|
||||
@@ -887,31 +857,32 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.204"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.204"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.120"
|
||||
version = "1.0.135"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
@@ -929,20 +900,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "simdutf8"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "stdio-perftest"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
@@ -972,34 +937,22 @@ version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.52"
|
||||
version = "2.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn_derive"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
@@ -1008,9 +961,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
|
||||
checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -1023,15 +976,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.6"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.21.1"
|
||||
version = "0.22.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
@@ -1044,8 +997,8 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@@ -1057,9 +1010,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "typewit"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6fb9ae6a3cafaf0a5d14c2302ca525f9ae8e07a0f0e6949de88d882c37a6e24"
|
||||
checksum = "cb77c29baba9e4d3a6182d51fa75e3215c7fd1dab8f4ea9d107c716878e55fc0"
|
||||
dependencies = [
|
||||
"typewit_proc_macros",
|
||||
]
|
||||
@@ -1072,9 +1025,9 @@ checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -1090,21 +1043,21 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
@@ -1116,42 +1069,20 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
@@ -1222,9 +1153,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.40"
|
||||
version = "0.6.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
|
||||
checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -1247,20 +1178,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.32"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
"proc-macro2 1.0.92",
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
@@ -9,9 +9,9 @@ proc-macro = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.35"
|
||||
syn = { version = "2.0.52" }
|
||||
quote = "1.0.38"
|
||||
syn = { version = "2.0.95" }
|
||||
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||
proc-macro2 = "1.0.78"
|
||||
darling = "0.20.8"
|
||||
itertools = "0.13.0"
|
||||
proc-macro2 = "1.0.92"
|
||||
darling = "0.20.10"
|
||||
itertools = "0.14.0"
|
||||
@@ -3,28 +3,28 @@ use quote::ToTokens;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
pub fn add_trait_bounds(mut generics: syn::Generics, bound: syn::TypeParamBound) -> syn::Generics {
|
||||
for param in &mut generics.params {
|
||||
if let syn::GenericParam::Type(ref mut type_param) = *param {
|
||||
type_param.bounds.push(bound.clone())
|
||||
}
|
||||
}
|
||||
generics
|
||||
for param in &mut generics.params {
|
||||
if let syn::GenericParam::Type(ref mut type_param) = *param {
|
||||
type_param.bounds.push(bound.clone())
|
||||
}
|
||||
}
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn destructure(fields: &syn::Fields) -> Option<pm2::TokenStream> {
|
||||
match fields {
|
||||
syn::Fields::Unit => None,
|
||||
syn::Fields::Named(_) => {
|
||||
let field_list = fields.iter().map(|f| f.ident.as_ref().unwrap());
|
||||
Some(quote! { { #(#field_list),* } })
|
||||
},
|
||||
syn::Fields::Unnamed(un) => {
|
||||
let field_list = (0..fields.len()).map(|i| pos_field_name(i, un.span()));
|
||||
Some(quote! { ( #(#field_list),* ) })
|
||||
},
|
||||
}
|
||||
match fields {
|
||||
syn::Fields::Unit => None,
|
||||
syn::Fields::Named(_) => {
|
||||
let field_list = fields.iter().map(|f| f.ident.as_ref().unwrap());
|
||||
Some(quote! { { #(#field_list),* } })
|
||||
},
|
||||
syn::Fields::Unnamed(un) => {
|
||||
let field_list = (0..fields.len()).map(|i| pos_field_name(i, un.span()));
|
||||
Some(quote! { ( #(#field_list),* ) })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pos_field_name(i: usize, span: pm2::Span) -> pm2::TokenStream {
|
||||
syn::Ident::new(&format!("field_{i}"), span).to_token_stream()
|
||||
syn::Ident::new(&format!("field_{i}"), span).to_token_stream()
|
||||
}
|
||||
@@ -4,53 +4,53 @@ use proc_macro2 as pm2;
|
||||
use crate::common::add_trait_bounds;
|
||||
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as syn::DeriveInput);
|
||||
let generics = add_trait_bounds(input.generics, parse_quote!(orchid_api_traits::Decode));
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
let name = input.ident;
|
||||
let decode = decode_body(&input.data);
|
||||
let expanded = quote! {
|
||||
impl #impl_generics orchid_api_traits::Decode for #name #ty_generics #where_clause {
|
||||
fn decode<R: std::io::Read + ?Sized>(read: &mut R) -> Self { #decode }
|
||||
}
|
||||
};
|
||||
TokenStream::from(expanded)
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as syn::DeriveInput);
|
||||
let generics = add_trait_bounds(input.generics, parse_quote!(orchid_api_traits::Decode));
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
let name = input.ident;
|
||||
let decode = decode_body(&input.data);
|
||||
let expanded = quote! {
|
||||
impl #impl_generics orchid_api_traits::Decode for #name #ty_generics #where_clause {
|
||||
fn decode<R: std::io::Read + ?Sized>(read: &mut R) -> Self { #decode }
|
||||
}
|
||||
};
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
fn decode_fields(fields: &syn::Fields) -> pm2::TokenStream {
|
||||
match fields {
|
||||
syn::Fields::Unit => quote! {},
|
||||
syn::Fields::Named(_) => {
|
||||
let names = fields.iter().map(|f| f.ident.as_ref().unwrap());
|
||||
quote! { { #( #names: orchid_api_traits::Decode::decode(read), )* } }
|
||||
},
|
||||
syn::Fields::Unnamed(_) => {
|
||||
let exprs = fields.iter().map(|_| quote! { orchid_api_traits::Decode::decode(read), });
|
||||
quote! { ( #( #exprs )* ) }
|
||||
},
|
||||
}
|
||||
match fields {
|
||||
syn::Fields::Unit => quote! {},
|
||||
syn::Fields::Named(_) => {
|
||||
let names = fields.iter().map(|f| f.ident.as_ref().unwrap());
|
||||
quote! { { #( #names: orchid_api_traits::Decode::decode(read), )* } }
|
||||
},
|
||||
syn::Fields::Unnamed(_) => {
|
||||
let exprs = fields.iter().map(|_| quote! { orchid_api_traits::Decode::decode(read), });
|
||||
quote! { ( #( #exprs )* ) }
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_body(data: &syn::Data) -> proc_macro2::TokenStream {
|
||||
match data {
|
||||
syn::Data::Union(_) => panic!("Unions can't be deserialized"),
|
||||
syn::Data::Struct(str) => {
|
||||
let fields = decode_fields(&str.fields);
|
||||
quote! { Self #fields }
|
||||
},
|
||||
syn::Data::Enum(en) => {
|
||||
let opts = en.variants.iter().enumerate().map(|(i, v @ syn::Variant { ident, .. })| {
|
||||
let fields = decode_fields(&v.fields);
|
||||
let id = i as u8;
|
||||
quote! { #id => Self::#ident #fields, }
|
||||
});
|
||||
quote! {
|
||||
match <u8 as orchid_api_traits::Decode>::decode(read) {
|
||||
#(#opts)*
|
||||
x => panic!("Unrecognized enum kind {x}")
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
match data {
|
||||
syn::Data::Union(_) => panic!("Unions can't be deserialized"),
|
||||
syn::Data::Struct(str) => {
|
||||
let fields = decode_fields(&str.fields);
|
||||
quote! { Self #fields }
|
||||
},
|
||||
syn::Data::Enum(en) => {
|
||||
let opts = en.variants.iter().enumerate().map(|(i, v @ syn::Variant { ident, .. })| {
|
||||
let fields = decode_fields(&v.fields);
|
||||
let id = i as u8;
|
||||
quote! { #id => Self::#ident #fields, }
|
||||
});
|
||||
quote! {
|
||||
match <u8 as orchid_api_traits::Decode>::decode(read) {
|
||||
#(#opts)*
|
||||
x => panic!("Unrecognized enum kind {x}")
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -6,61 +6,61 @@ use syn::spanned::Spanned;
|
||||
use crate::common::{add_trait_bounds, destructure, pos_field_name};
|
||||
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as syn::DeriveInput);
|
||||
let e_generics = add_trait_bounds(input.generics, parse_quote!(orchid_api_traits::Encode));
|
||||
let (e_impl_generics, e_ty_generics, e_where_clause) = e_generics.split_for_impl();
|
||||
let name = input.ident;
|
||||
let encode = encode_body(&input.data);
|
||||
let expanded = quote! {
|
||||
impl #e_impl_generics orchid_api_traits::Encode for #name #e_ty_generics #e_where_clause {
|
||||
fn encode<W: std::io::Write + ?Sized>(&self, write: &mut W) { #encode }
|
||||
}
|
||||
};
|
||||
TokenStream::from(expanded)
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as syn::DeriveInput);
|
||||
let e_generics = add_trait_bounds(input.generics, parse_quote!(orchid_api_traits::Encode));
|
||||
let (e_impl_generics, e_ty_generics, e_where_clause) = e_generics.split_for_impl();
|
||||
let name = input.ident;
|
||||
let encode = encode_body(&input.data);
|
||||
let expanded = quote! {
|
||||
impl #e_impl_generics orchid_api_traits::Encode for #name #e_ty_generics #e_where_clause {
|
||||
fn encode<W: std::io::Write + ?Sized>(&self, write: &mut W) { #encode }
|
||||
}
|
||||
};
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
fn encode_body(data: &syn::Data) -> Option<pm2::TokenStream> {
|
||||
match data {
|
||||
syn::Data::Union(_) => panic!("Unions can't be deserialized"),
|
||||
syn::Data::Struct(str) => {
|
||||
let dest = destructure(&str.fields)?;
|
||||
let body = encode_items(&str.fields);
|
||||
Some(quote! {
|
||||
let Self #dest = &self;
|
||||
#body
|
||||
})
|
||||
},
|
||||
syn::Data::Enum(en) => {
|
||||
let options = en.variants.iter().enumerate().map(|(i, v @ syn::Variant { ident, .. })| {
|
||||
let dest = destructure(&v.fields).unwrap_or_default();
|
||||
let body = encode_items(&v.fields);
|
||||
quote! {
|
||||
Self::#ident #dest => {
|
||||
(#i as u8).encode(write);
|
||||
#body
|
||||
}
|
||||
}
|
||||
});
|
||||
Some(quote! {
|
||||
match self {
|
||||
#(#options)*
|
||||
_ => unreachable!("Autogenerated encode impl for all possible variants"),
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
match data {
|
||||
syn::Data::Union(_) => panic!("Unions can't be deserialized"),
|
||||
syn::Data::Struct(str) => {
|
||||
let dest = destructure(&str.fields)?;
|
||||
let body = encode_items(&str.fields);
|
||||
Some(quote! {
|
||||
let Self #dest = &self;
|
||||
#body
|
||||
})
|
||||
},
|
||||
syn::Data::Enum(en) => {
|
||||
let options = en.variants.iter().enumerate().map(|(i, v @ syn::Variant { ident, .. })| {
|
||||
let dest = destructure(&v.fields).unwrap_or_default();
|
||||
let body = encode_items(&v.fields);
|
||||
quote! {
|
||||
Self::#ident #dest => {
|
||||
(#i as u8).encode(write);
|
||||
#body
|
||||
}
|
||||
}
|
||||
});
|
||||
Some(quote! {
|
||||
match self {
|
||||
#(#options)*
|
||||
_ => unreachable!("Autogenerated encode impl for all possible variants"),
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_names<T: ToTokens>(names: impl Iterator<Item = T>) -> pm2::TokenStream {
|
||||
quote! { #( #names .encode(write); )* }
|
||||
quote! { #( #names .encode(write); )* }
|
||||
}
|
||||
|
||||
fn encode_items(fields: &syn::Fields) -> Option<pm2::TokenStream> {
|
||||
match fields {
|
||||
syn::Fields::Unit => None,
|
||||
syn::Fields::Named(_) => Some(encode_names(fields.iter().map(|f| f.ident.as_ref().unwrap()))),
|
||||
syn::Fields::Unnamed(un) =>
|
||||
Some(encode_names((0..fields.len()).map(|i| pos_field_name(i, un.span())))),
|
||||
}
|
||||
match fields {
|
||||
syn::Fields::Unit => None,
|
||||
syn::Fields::Named(_) => Some(encode_names(fields.iter().map(|f| f.ident.as_ref().unwrap()))),
|
||||
syn::Fields::Unnamed(un) =>
|
||||
Some(encode_names((0..fields.len()).map(|i| pos_field_name(i, un.span())))),
|
||||
}
|
||||
}
|
||||
+103
-103
@@ -7,118 +7,118 @@ use proc_macro2 as pm2;
|
||||
use syn::DeriveInput;
|
||||
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as syn::DeriveInput);
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let name = &input.ident;
|
||||
let extendable = is_extendable(&input);
|
||||
let is_leaf_val = if extendable { quote!(TLFalse) } else { quote!(TLTrue) };
|
||||
match get_ancestry(&input) {
|
||||
None => TokenStream::from(quote! {
|
||||
impl #impl_generics orchid_api_traits::InHierarchy for #name #ty_generics #where_clause {
|
||||
type IsRoot = orchid_api_traits::TLTrue;
|
||||
type IsLeaf = orchid_api_traits:: #is_leaf_val ;
|
||||
}
|
||||
}),
|
||||
Some(ancestry) => {
|
||||
let parent = ancestry[0].clone();
|
||||
let casts = gen_casts(&ancestry[..], "e!(#name));
|
||||
TokenStream::from(quote! {
|
||||
#casts
|
||||
impl #impl_generics orchid_api_traits::InHierarchy for #name #ty_generics #where_clause {
|
||||
type IsRoot = orchid_api_traits::TLFalse;
|
||||
type IsLeaf = orchid_api_traits:: #is_leaf_val ;
|
||||
}
|
||||
impl #impl_generics orchid_api_traits::Extends for #name #ty_generics #where_clause {
|
||||
type Parent = #parent;
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as syn::DeriveInput);
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let name = &input.ident;
|
||||
let extendable = is_extendable(&input);
|
||||
let is_leaf_val = if extendable { quote!(TLFalse) } else { quote!(TLTrue) };
|
||||
match get_ancestry(&input) {
|
||||
None => TokenStream::from(quote! {
|
||||
impl #impl_generics orchid_api_traits::InHierarchy for #name #ty_generics #where_clause {
|
||||
type IsRoot = orchid_api_traits::TLTrue;
|
||||
type IsLeaf = orchid_api_traits:: #is_leaf_val ;
|
||||
}
|
||||
}),
|
||||
Some(ancestry) => {
|
||||
let parent = ancestry[0].clone();
|
||||
let casts = gen_casts(&ancestry[..], "e!(#name));
|
||||
TokenStream::from(quote! {
|
||||
#casts
|
||||
impl #impl_generics orchid_api_traits::InHierarchy for #name #ty_generics #where_clause {
|
||||
type IsRoot = orchid_api_traits::TLFalse;
|
||||
type IsLeaf = orchid_api_traits:: #is_leaf_val ;
|
||||
}
|
||||
impl #impl_generics orchid_api_traits::Extends for #name #ty_generics #where_clause {
|
||||
type Parent = #parent;
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_casts(ancestry: &[pm2::TokenStream], this: &pm2::TokenStream) -> pm2::TokenStream {
|
||||
let from_impls = iter::once(this).chain(ancestry.iter()).tuple_windows().map(|(prev, cur)| {
|
||||
quote! {
|
||||
impl From<#this> for #cur {
|
||||
fn from(value: #this) -> Self {
|
||||
#cur::#prev(value.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let try_from_impls = (1..=ancestry.len()).map(|len| {
|
||||
let (orig, inter) = ancestry[..len].split_last().unwrap();
|
||||
fn gen_chk(r: &[pm2::TokenStream], last: &pm2::TokenStream) -> pm2::TokenStream {
|
||||
match r.split_last() {
|
||||
None => quote! { #last (_) => true },
|
||||
Some((ty, tail)) => {
|
||||
let sub = gen_chk(tail, last);
|
||||
quote! {
|
||||
#ty ( value ) => match value {
|
||||
#ty:: #sub ,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let chk = gen_chk(inter, this);
|
||||
fn gen_unpk(r: &[pm2::TokenStream], last: &pm2::TokenStream) -> pm2::TokenStream {
|
||||
match r.split_last() {
|
||||
None => quote! { #last ( value ) => value },
|
||||
Some((ty, tail)) => {
|
||||
let sub = gen_unpk(tail, last);
|
||||
quote! {
|
||||
#ty ( value ) => match value {
|
||||
#ty:: #sub ,
|
||||
_ => unreachable!("Checked above!"),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let unpk = gen_unpk(inter, this);
|
||||
quote! {
|
||||
impl TryFrom<#orig> for #this {
|
||||
type Error = #orig;
|
||||
fn try_from(value: #orig) -> Result<Self, Self::Error> {
|
||||
let can_cast = match &value {
|
||||
#orig:: #chk ,
|
||||
_ => false
|
||||
};
|
||||
if !can_cast { return Err(value) }
|
||||
Ok ( match value {
|
||||
#orig:: #unpk ,
|
||||
_ => unreachable!("Checked above!")
|
||||
} )
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
from_impls.chain(try_from_impls).flatten().collect()
|
||||
let from_impls = iter::once(this).chain(ancestry.iter()).tuple_windows().map(|(prev, cur)| {
|
||||
quote! {
|
||||
impl From<#this> for #cur {
|
||||
fn from(value: #this) -> Self {
|
||||
#cur::#prev(value.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let try_from_impls = (1..=ancestry.len()).map(|len| {
|
||||
let (orig, inter) = ancestry[..len].split_last().unwrap();
|
||||
fn gen_chk(r: &[pm2::TokenStream], last: &pm2::TokenStream) -> pm2::TokenStream {
|
||||
match r.split_last() {
|
||||
None => quote! { #last (_) => true },
|
||||
Some((ty, tail)) => {
|
||||
let sub = gen_chk(tail, last);
|
||||
quote! {
|
||||
#ty ( value ) => match value {
|
||||
#ty:: #sub ,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let chk = gen_chk(inter, this);
|
||||
fn gen_unpk(r: &[pm2::TokenStream], last: &pm2::TokenStream) -> pm2::TokenStream {
|
||||
match r.split_last() {
|
||||
None => quote! { #last ( value ) => value },
|
||||
Some((ty, tail)) => {
|
||||
let sub = gen_unpk(tail, last);
|
||||
quote! {
|
||||
#ty ( value ) => match value {
|
||||
#ty:: #sub ,
|
||||
_ => unreachable!("Checked above!"),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let unpk = gen_unpk(inter, this);
|
||||
quote! {
|
||||
impl TryFrom<#orig> for #this {
|
||||
type Error = #orig;
|
||||
fn try_from(value: #orig) -> Result<Self, Self::Error> {
|
||||
let can_cast = match &value {
|
||||
#orig:: #chk ,
|
||||
_ => false
|
||||
};
|
||||
if !can_cast { return Err(value) }
|
||||
Ok ( match value {
|
||||
#orig:: #unpk ,
|
||||
_ => unreachable!("Checked above!")
|
||||
} )
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
from_impls.chain(try_from_impls).flatten().collect()
|
||||
}
|
||||
|
||||
fn get_ancestry(input: &DeriveInput) -> Option<Vec<pm2::TokenStream>> {
|
||||
input.attrs.iter().find(|a| a.path().get_ident().is_some_and(|i| *i == "extends")).map(|attr| {
|
||||
match &attr.meta {
|
||||
syn::Meta::List(list) => (list.tokens.clone().into_iter())
|
||||
.batching(|it| {
|
||||
let grp: pm2::TokenStream =
|
||||
it.take_while(|t| {
|
||||
if let TokenTree::Punct(punct) = t { punct.as_char() != ',' } else { true }
|
||||
})
|
||||
.collect();
|
||||
(!grp.is_empty()).then_some(grp)
|
||||
})
|
||||
.collect(),
|
||||
_ => panic!("The correct format of the parent macro is #[parent(SomeParentType)]"),
|
||||
}
|
||||
})
|
||||
input.attrs.iter().find(|a| a.path().get_ident().is_some_and(|i| *i == "extends")).map(|attr| {
|
||||
match &attr.meta {
|
||||
syn::Meta::List(list) => (list.tokens.clone().into_iter())
|
||||
.batching(|it| {
|
||||
let grp: pm2::TokenStream =
|
||||
it.take_while(|t| {
|
||||
if let TokenTree::Punct(punct) = t { punct.as_char() != ',' } else { true }
|
||||
})
|
||||
.collect();
|
||||
(!grp.is_empty()).then_some(grp)
|
||||
})
|
||||
.collect(),
|
||||
_ => panic!("The correct format of the parent macro is #[parent(SomeParentType)]"),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn is_extendable(input: &DeriveInput) -> bool {
|
||||
input.attrs.iter().any(|a| a.path().get_ident().is_some_and(|i| *i == "extendable"))
|
||||
input.attrs.iter().any(|a| a.path().get_ident().is_some_and(|i| *i == "extendable"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -23,5 +23,5 @@ pub fn hierarchy(input: TokenStream) -> TokenStream { hierarchy::derive(input) }
|
||||
|
||||
#[proc_macro_derive(Coding)]
|
||||
pub fn coding(input: TokenStream) -> TokenStream {
|
||||
decode(input.clone()).into_iter().chain(encode(input)).collect()
|
||||
decode(input.clone()).into_iter().chain(encode(input)).collect()
|
||||
}
|
||||
@@ -6,6 +6,6 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.13.0"
|
||||
itertools = "0.14.0"
|
||||
never = "0.1.0"
|
||||
ordered-float = "4.2"
|
||||
ordered-float = "4.6.0"
|
||||
+136
-136
@@ -13,36 +13,36 @@ use ordered_float::NotNan;
|
||||
use crate::encode_enum;
|
||||
|
||||
pub trait Decode {
|
||||
/// Decode an instance from the beginning of the buffer. Return the decoded
|
||||
/// data and the remaining buffer.
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self;
|
||||
/// Decode an instance from the beginning of the buffer. Return the decoded
|
||||
/// data and the remaining buffer.
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self;
|
||||
}
|
||||
pub trait Encode {
|
||||
/// Append an instance of the struct to the buffer
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W);
|
||||
/// Append an instance of the struct to the buffer
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W);
|
||||
}
|
||||
pub trait Coding: Encode + Decode + Clone {
|
||||
fn get_decoder<T>(map: impl Fn(Self) -> T + 'static) -> impl Fn(&mut dyn Read) -> T {
|
||||
move |r| map(Self::decode(r))
|
||||
}
|
||||
fn get_decoder<T>(map: impl Fn(Self) -> T + 'static) -> impl Fn(&mut dyn Read) -> T {
|
||||
move |r| map(Self::decode(r))
|
||||
}
|
||||
}
|
||||
impl<T: Encode + Decode + Clone> Coding for T {}
|
||||
|
||||
macro_rules! num_impl {
|
||||
($number:ty) => {
|
||||
impl Decode for $number {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let mut bytes = [0u8; (<$number>::BITS / 8) as usize];
|
||||
read.read_exact(&mut bytes).unwrap();
|
||||
<$number>::from_be_bytes(bytes)
|
||||
}
|
||||
}
|
||||
impl Encode for $number {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write.write_all(&self.to_be_bytes()).expect("Could not write number")
|
||||
}
|
||||
}
|
||||
};
|
||||
($number:ty) => {
|
||||
impl Decode for $number {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let mut bytes = [0u8; (<$number>::BITS / 8) as usize];
|
||||
read.read_exact(&mut bytes).unwrap();
|
||||
<$number>::from_be_bytes(bytes)
|
||||
}
|
||||
}
|
||||
impl Encode for $number {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write.write_all(&self.to_be_bytes()).expect("Could not write number")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
num_impl!(u128);
|
||||
num_impl!(u64);
|
||||
@@ -56,14 +56,14 @@ num_impl!(i16);
|
||||
num_impl!(i8);
|
||||
|
||||
macro_rules! nonzero_impl {
|
||||
($name:ty) => {
|
||||
impl Decode for $name {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { Self::new(Decode::decode(read)).unwrap() }
|
||||
}
|
||||
impl Encode for $name {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { self.get().encode(write) }
|
||||
}
|
||||
};
|
||||
($name:ty) => {
|
||||
impl Decode for $name {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { Self::new(Decode::decode(read)).unwrap() }
|
||||
}
|
||||
impl Encode for $name {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { self.get().encode(write) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
nonzero_impl!(std::num::NonZeroU8);
|
||||
@@ -78,111 +78,111 @@ nonzero_impl!(std::num::NonZeroI64);
|
||||
nonzero_impl!(std::num::NonZeroI128);
|
||||
|
||||
impl<T: Encode + ?Sized> Encode for &T {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (**self).encode(write) }
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (**self).encode(write) }
|
||||
}
|
||||
macro_rules! float_impl {
|
||||
($t:ty, $size:expr) => {
|
||||
impl Decode for NotNan<$t> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let mut bytes = [0u8; $size];
|
||||
read.read_exact(&mut bytes).unwrap();
|
||||
NotNan::new(<$t>::from_be_bytes(bytes)).expect("Float was NaN")
|
||||
}
|
||||
}
|
||||
impl Encode for NotNan<$t> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write.write_all(&self.as_ref().to_be_bytes()).expect("Could not write number")
|
||||
}
|
||||
}
|
||||
};
|
||||
($t:ty, $size:expr) => {
|
||||
impl Decode for NotNan<$t> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let mut bytes = [0u8; $size];
|
||||
read.read_exact(&mut bytes).unwrap();
|
||||
NotNan::new(<$t>::from_be_bytes(bytes)).expect("Float was NaN")
|
||||
}
|
||||
}
|
||||
impl Encode for NotNan<$t> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write.write_all(&self.as_ref().to_be_bytes()).expect("Could not write number")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
float_impl!(f64, 8);
|
||||
float_impl!(f32, 4);
|
||||
|
||||
impl Decode for String {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let len = u64::decode(read).try_into().unwrap();
|
||||
let mut data = vec![0u8; len];
|
||||
read.read_exact(&mut data).unwrap();
|
||||
std::str::from_utf8(&data).expect("String invalid UTF-8").to_owned()
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let len = u64::decode(read).try_into().unwrap();
|
||||
let mut data = vec![0u8; len];
|
||||
read.read_exact(&mut data).unwrap();
|
||||
std::str::from_utf8(&data).expect("String invalid UTF-8").to_owned()
|
||||
}
|
||||
}
|
||||
impl Encode for String {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
write.write_all(self.as_bytes()).unwrap()
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
write.write_all(self.as_bytes()).unwrap()
|
||||
}
|
||||
}
|
||||
impl Encode for str {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
write.write_all(self.as_bytes()).unwrap()
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
write.write_all(self.as_bytes()).unwrap()
|
||||
}
|
||||
}
|
||||
impl<T: Decode> Decode for Vec<T> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let len = u64::decode(read).try_into().unwrap();
|
||||
iter::repeat_with(|| T::decode(read)).take(len).collect()
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let len = u64::decode(read).try_into().unwrap();
|
||||
iter::repeat_with(|| T::decode(read)).take(len).collect()
|
||||
}
|
||||
}
|
||||
impl<T: Encode> Encode for Vec<T> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
self.iter().for_each(|t| t.encode(write));
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
self.iter().for_each(|t| t.encode(write));
|
||||
}
|
||||
}
|
||||
impl<T: Encode> Encode for [T] {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
self.iter().for_each(|t| t.encode(write));
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
self.iter().for_each(|t| t.encode(write));
|
||||
}
|
||||
}
|
||||
impl<T: Decode> Decode for Option<T> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
match u8::decode(read) {
|
||||
0 => None,
|
||||
1 => Some(T::decode(read)),
|
||||
x => panic!("{x} is not a valid option value"),
|
||||
}
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
match u8::decode(read) {
|
||||
0 => None,
|
||||
1 => Some(T::decode(read)),
|
||||
x => panic!("{x} is not a valid option value"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Encode> Encode for Option<T> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
let t = if let Some(t) = self { t } else { return 0u8.encode(write) };
|
||||
1u8.encode(write);
|
||||
t.encode(write);
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
let t = if let Some(t) = self { t } else { return 0u8.encode(write) };
|
||||
1u8.encode(write);
|
||||
t.encode(write);
|
||||
}
|
||||
}
|
||||
impl<T: Decode, E: Decode> Decode for Result<T, E> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
match u8::decode(read) {
|
||||
0 => Self::Ok(T::decode(read)),
|
||||
1 => Self::Err(E::decode(read)),
|
||||
x => panic!("Invalid Result tag {x}"),
|
||||
}
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
match u8::decode(read) {
|
||||
0 => Self::Ok(T::decode(read)),
|
||||
1 => Self::Err(E::decode(read)),
|
||||
x => panic!("Invalid Result tag {x}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Encode, E: Encode> Encode for Result<T, E> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
match self {
|
||||
Ok(t) => encode_enum(write, 0, |w| t.encode(w)),
|
||||
Err(e) => encode_enum(write, 1, |w| e.encode(w)),
|
||||
}
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
match self {
|
||||
Ok(t) => encode_enum(write, 0, |w| t.encode(w)),
|
||||
Err(e) => encode_enum(write, 1, |w| e.encode(w)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<K: Decode + Eq + Hash, V: Decode> Decode for HashMap<K, V> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let len = u64::decode(read).try_into().unwrap();
|
||||
iter::repeat_with(|| <(K, V)>::decode(read)).take(len).collect()
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let len = u64::decode(read).try_into().unwrap();
|
||||
iter::repeat_with(|| <(K, V)>::decode(read)).take(len).collect()
|
||||
}
|
||||
}
|
||||
impl<K: Encode + Eq + Hash, V: Encode> Encode for HashMap<K, V> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
self.iter().for_each(|pair| pair.encode(write));
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
u64::try_from(self.len()).unwrap().encode(write);
|
||||
self.iter().for_each(|pair| pair.encode(write));
|
||||
}
|
||||
}
|
||||
macro_rules! tuple {
|
||||
(($($t:ident)*) ($($T:ident)*)) => {
|
||||
@@ -216,40 +216,40 @@ tuple!((t u v x y z a b c d e f g h i) (T U V X Y Z A B C D E F G H I));
|
||||
tuple!((t u v x y z a b c d e f g h i j) (T U V X Y Z A B C D E F G H I J)); // 16
|
||||
|
||||
impl Decode for () {
|
||||
fn decode<R: Read + ?Sized>(_: &mut R) -> Self {}
|
||||
fn decode<R: Read + ?Sized>(_: &mut R) -> Self {}
|
||||
}
|
||||
impl Encode for () {
|
||||
fn encode<W: Write + ?Sized>(&self, _: &mut W) {}
|
||||
fn encode<W: Write + ?Sized>(&self, _: &mut W) {}
|
||||
}
|
||||
impl Decode for Never {
|
||||
fn decode<R: Read + ?Sized>(_: &mut R) -> Self {
|
||||
unreachable!("A value of Never cannot exist so it can't have been serialized");
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(_: &mut R) -> Self {
|
||||
unreachable!("A value of Never cannot exist so it can't have been serialized");
|
||||
}
|
||||
}
|
||||
impl Encode for Never {
|
||||
fn encode<W: Write + ?Sized>(&self, _: &mut W) { match *self {} }
|
||||
fn encode<W: Write + ?Sized>(&self, _: &mut W) { match *self {} }
|
||||
}
|
||||
impl Decode for bool {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let mut buf = [0];
|
||||
read.read_exact(&mut buf).unwrap();
|
||||
buf[0] != 0
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
let mut buf = [0];
|
||||
read.read_exact(&mut buf).unwrap();
|
||||
buf[0] != 0
|
||||
}
|
||||
}
|
||||
impl Encode for bool {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write.write_all(&[if *self { 0xff } else { 0 }]).unwrap()
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write.write_all(&[if *self { 0xff } else { 0 }]).unwrap()
|
||||
}
|
||||
}
|
||||
impl<T: Decode, const N: usize> Decode for [T; N] {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
// TODO: figure out how to do this in safe rust on the stack
|
||||
((0..N).map(|_| T::decode(read)).collect::<Vec<_>>().try_into())
|
||||
.unwrap_or_else(|_| unreachable!("The length of this iterator is statically known"))
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
// TODO: figure out how to do this in safe rust on the stack
|
||||
((0..N).map(|_| T::decode(read)).collect::<Vec<_>>().try_into())
|
||||
.unwrap_or_else(|_| unreachable!("The length of this iterator is statically known"))
|
||||
}
|
||||
}
|
||||
impl<T: Encode, const N: usize> Encode for [T; N] {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { self.iter().for_each(|t| t.encode(write)) }
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { self.iter().for_each(|t| t.encode(write)) }
|
||||
}
|
||||
|
||||
macro_rules! two_end_range {
|
||||
@@ -271,14 +271,14 @@ two_end_range!(x, Range, .., x.start, x.end);
|
||||
two_end_range!(x, RangeInclusive, ..=, x.start(), x.end());
|
||||
|
||||
macro_rules! smart_ptr {
|
||||
($name:tt) => {
|
||||
impl<T: Decode> Decode for $name<T> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { $name::new(T::decode(read)) }
|
||||
}
|
||||
impl<T: Encode> Encode for $name<T> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (**self).encode(write) }
|
||||
}
|
||||
};
|
||||
($name:tt) => {
|
||||
impl<T: Decode> Decode for $name<T> {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { $name::new(T::decode(read)) }
|
||||
}
|
||||
impl<T: Encode> Encode for $name<T> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (**self).encode(write) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
smart_ptr!(Arc);
|
||||
@@ -288,15 +288,15 @@ smart_ptr!(Box);
|
||||
impl<T: ?Sized + ToOwned> Decode for Cow<'_, T>
|
||||
where T::Owned: Decode
|
||||
{
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { Cow::Owned(T::Owned::decode(read)) }
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { Cow::Owned(T::Owned::decode(read)) }
|
||||
}
|
||||
impl<T: ?Sized + Encode + ToOwned> Encode for Cow<'_, T> {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (**self).encode(write) }
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (**self).encode(write) }
|
||||
}
|
||||
|
||||
impl Decode for char {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { char::from_u32(u32::decode(read)).unwrap() }
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self { char::from_u32(u32::decode(read)).unwrap() }
|
||||
}
|
||||
impl Encode for char {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (*self as u32).encode(write) }
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) { (*self as u32).encode(write) }
|
||||
}
|
||||
@@ -5,32 +5,32 @@ use itertools::{Chunk, Itertools};
|
||||
use crate::Encode;
|
||||
|
||||
pub fn encode_enum<W: Write + ?Sized>(write: &mut W, id: u8, f: impl FnOnce(&mut W)) {
|
||||
id.encode(write);
|
||||
f(write)
|
||||
id.encode(write);
|
||||
f(write)
|
||||
}
|
||||
|
||||
pub fn write_exact<W: Write + ?Sized>(write: &mut W, bytes: &'static [u8]) {
|
||||
write.write_all(bytes).expect("Failed to write exact bytes")
|
||||
write.write_all(bytes).expect("Failed to write exact bytes")
|
||||
}
|
||||
|
||||
pub fn print_bytes(b: &[u8]) -> String {
|
||||
(b.iter().map(|b| format!("{b:02x}")))
|
||||
.chunks(4)
|
||||
.into_iter()
|
||||
.map(|mut c: Chunk<_>| c.join(" "))
|
||||
.join(" ")
|
||||
(b.iter().map(|b| format!("{b:02x}")))
|
||||
.chunks(4)
|
||||
.into_iter()
|
||||
.map(|mut c: Chunk<_>| c.join(" "))
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
pub fn read_exact<R: Read + ?Sized>(read: &mut R, bytes: &'static [u8]) {
|
||||
let mut data = vec![0u8; bytes.len()];
|
||||
read.read_exact(&mut data).expect("Failed to read bytes");
|
||||
if data != bytes {
|
||||
panic!("Wrong bytes!\nExpected: {}\nFound: {}", print_bytes(bytes), print_bytes(&data));
|
||||
}
|
||||
let mut data = vec![0u8; bytes.len()];
|
||||
read.read_exact(&mut data).expect("Failed to read bytes");
|
||||
if data != bytes {
|
||||
panic!("Wrong bytes!\nExpected: {}\nFound: {}", print_bytes(bytes), print_bytes(&data));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enc_vec(enc: &impl Encode) -> Vec<u8> {
|
||||
let mut vec = Vec::new();
|
||||
enc.encode(&mut vec);
|
||||
vec
|
||||
let mut vec = Vec::new();
|
||||
enc.encode(&mut vec);
|
||||
vec
|
||||
}
|
||||
@@ -11,54 +11,54 @@ impl TLBool for TLFalse {}
|
||||
/// A type that implements [Hierarchy]. Used to select implementations of traits
|
||||
/// on the hierarchy
|
||||
pub trait InHierarchy: Clone {
|
||||
/// Indicates that this hierarchy element is a leaf. Leaves can never have
|
||||
/// children
|
||||
type IsLeaf: TLBool;
|
||||
/// Indicates that this hierarchy element is a root. Roots can never have
|
||||
/// parents
|
||||
type IsRoot: TLBool;
|
||||
/// Indicates that this hierarchy element is a leaf. Leaves can never have
|
||||
/// children
|
||||
type IsLeaf: TLBool;
|
||||
/// Indicates that this hierarchy element is a root. Roots can never have
|
||||
/// parents
|
||||
type IsRoot: TLBool;
|
||||
}
|
||||
/// A type that derives from a parent type.
|
||||
pub trait Extends: InHierarchy<IsRoot = TLFalse> + Into<Self::Parent> {
|
||||
/// Specify the immediate parent of this type. This guides the
|
||||
type Parent: InHierarchy<IsLeaf = TLFalse>
|
||||
+ TryInto<Self>
|
||||
+ UnderRootImpl<<Self::Parent as InHierarchy>::IsRoot>;
|
||||
/// Specify the immediate parent of this type. This guides the
|
||||
type Parent: InHierarchy<IsLeaf = TLFalse>
|
||||
+ TryInto<Self>
|
||||
+ UnderRootImpl<<Self::Parent as InHierarchy>::IsRoot>;
|
||||
}
|
||||
|
||||
pub trait UnderRootImpl<IsRoot: TLBool>: Sized {
|
||||
type __Root: UnderRoot<IsRoot = TLTrue, Root = Self::__Root>;
|
||||
fn __into_root(self) -> Self::__Root;
|
||||
fn __try_from_root(root: Self::__Root) -> Result<Self, Self::__Root>;
|
||||
type __Root: UnderRoot<IsRoot = TLTrue, Root = Self::__Root>;
|
||||
fn __into_root(self) -> Self::__Root;
|
||||
fn __try_from_root(root: Self::__Root) -> Result<Self, Self::__Root>;
|
||||
}
|
||||
|
||||
pub trait UnderRoot: InHierarchy {
|
||||
type Root: UnderRoot<IsRoot = TLTrue, Root = Self::Root>;
|
||||
fn into_root(self) -> Self::Root;
|
||||
fn try_from_root(root: Self::Root) -> Result<Self, Self::Root>;
|
||||
type Root: UnderRoot<IsRoot = TLTrue, Root = Self::Root>;
|
||||
fn into_root(self) -> Self::Root;
|
||||
fn try_from_root(root: Self::Root) -> Result<Self, Self::Root>;
|
||||
}
|
||||
|
||||
impl<T: InHierarchy + UnderRootImpl<T::IsRoot>> UnderRoot for T {
|
||||
type Root = <Self as UnderRootImpl<<Self as InHierarchy>::IsRoot>>::__Root;
|
||||
fn into_root(self) -> Self::Root { self.__into_root() }
|
||||
fn try_from_root(root: Self::Root) -> Result<Self, Self::Root> { Self::__try_from_root(root) }
|
||||
type Root = <Self as UnderRootImpl<<Self as InHierarchy>::IsRoot>>::__Root;
|
||||
fn into_root(self) -> Self::Root { self.__into_root() }
|
||||
fn try_from_root(root: Self::Root) -> Result<Self, Self::Root> { Self::__try_from_root(root) }
|
||||
}
|
||||
|
||||
impl<T: InHierarchy<IsRoot = TLTrue>> UnderRootImpl<TLTrue> for T {
|
||||
type __Root = Self;
|
||||
fn __into_root(self) -> Self::__Root { self }
|
||||
fn __try_from_root(root: Self::__Root) -> Result<Self, Self::__Root> { Ok(root) }
|
||||
type __Root = Self;
|
||||
fn __into_root(self) -> Self::__Root { self }
|
||||
fn __try_from_root(root: Self::__Root) -> Result<Self, Self::__Root> { Ok(root) }
|
||||
}
|
||||
|
||||
impl<T: InHierarchy<IsRoot = TLFalse> + Extends> UnderRootImpl<TLFalse> for T {
|
||||
type __Root = <<Self as Extends>::Parent as UnderRootImpl<
|
||||
<<Self as Extends>::Parent as InHierarchy>::IsRoot,
|
||||
>>::__Root;
|
||||
fn __into_root(self) -> Self::__Root {
|
||||
<Self as Into<<Self as Extends>::Parent>>::into(self).into_root()
|
||||
}
|
||||
fn __try_from_root(root: Self::__Root) -> Result<Self, Self::__Root> {
|
||||
let parent = <Self as Extends>::Parent::try_from_root(root)?;
|
||||
parent.clone().try_into().map_err(|_| parent.into_root())
|
||||
}
|
||||
type __Root = <<Self as Extends>::Parent as UnderRootImpl<
|
||||
<<Self as Extends>::Parent as InHierarchy>::IsRoot,
|
||||
>>::__Root;
|
||||
fn __into_root(self) -> Self::__Root {
|
||||
<Self as Into<<Self as Extends>::Parent>>::into(self).into_root()
|
||||
}
|
||||
fn __try_from_root(root: Self::__Root) -> Result<Self, Self::__Root> {
|
||||
let parent = <Self as Extends>::Parent::try_from_root(root)?;
|
||||
parent.clone().try_into().map_err(|_| parent.into_root())
|
||||
}
|
||||
}
|
||||
@@ -2,20 +2,20 @@ use super::coding::Coding;
|
||||
use crate::helpers::enc_vec;
|
||||
|
||||
pub trait Request: Coding + Sized + Send + 'static {
|
||||
type Response: Coding + Send + 'static;
|
||||
type Response: Coding + Send + 'static;
|
||||
}
|
||||
|
||||
pub fn respond<R: Request>(_: &R, rep: R::Response) -> Vec<u8> { enc_vec(&rep) }
|
||||
pub fn respond_with<R: Request>(r: &R, f: impl FnOnce(&R) -> R::Response) -> Vec<u8> {
|
||||
respond(r, f(r))
|
||||
respond(r, f(r))
|
||||
}
|
||||
|
||||
pub trait Channel: 'static {
|
||||
type Req: Coding + Sized + Send + 'static;
|
||||
type Notif: Coding + Sized + Send + 'static;
|
||||
type Req: Coding + Sized + Send + 'static;
|
||||
type Notif: Coding + Sized + Send + 'static;
|
||||
}
|
||||
|
||||
pub trait MsgSet: Send + Sync + 'static {
|
||||
type In: Channel;
|
||||
type Out: Channel;
|
||||
type In: Channel;
|
||||
type Out: Channel;
|
||||
}
|
||||
@@ -6,6 +6,6 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
ordered-float = "4.2.0"
|
||||
ordered-float = "4.6.0"
|
||||
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
|
||||
+51
-49
@@ -3,7 +3,9 @@ use std::num::NonZeroU64;
|
||||
use orchid_api_derive::{Coding, Hierarchy};
|
||||
use orchid_api_traits::Request;
|
||||
|
||||
use crate::{ExprTicket, Expression, ExtHostReq, HostExtNotif, HostExtReq, OrcResult, SysId, TStrv};
|
||||
use crate::{
|
||||
ExprTicket, Expression, ExtHostReq, HostExtNotif, HostExtReq, OrcResult, SysId, TStrv,
|
||||
};
|
||||
|
||||
pub type AtomData = Vec<u8>;
|
||||
|
||||
@@ -15,34 +17,34 @@ pub struct AtomId(pub NonZeroU64);
|
||||
/// This has the same semantics as [Atom] except in that the owner is implied.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding)]
|
||||
pub struct LocalAtom {
|
||||
pub drop: Option<AtomId>,
|
||||
pub data: AtomData,
|
||||
pub drop: Option<AtomId>,
|
||||
pub data: AtomData,
|
||||
}
|
||||
impl LocalAtom {
|
||||
pub fn associate(self, owner: SysId) -> Atom { Atom { owner, drop: self.drop, data: self.data } }
|
||||
pub fn associate(self, owner: SysId) -> Atom { Atom { owner, drop: self.drop, data: self.data } }
|
||||
}
|
||||
|
||||
/// An atom representation that can be serialized and sent around. Atoms
|
||||
/// represent the smallest increment of work.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding)]
|
||||
pub struct Atom {
|
||||
/// Instance ID of the system that created the atom
|
||||
pub owner: SysId,
|
||||
/// Indicates how the owner should be notified when this atom is dropped.
|
||||
/// Construction is always explicit and atoms are never cloned.
|
||||
///
|
||||
/// Atoms with `drop == None` are also known as trivial, they can be
|
||||
/// duplicated and stored with no regard to expression lifetimes. NOTICE
|
||||
/// that this only applies to the atom. If it's referenced with an
|
||||
/// [ExprTicket], the ticket itself can still expire.
|
||||
///
|
||||
/// Notice also that the atoms still expire when the system is dropped, and
|
||||
/// are not portable across instances of the same system, so this doesn't
|
||||
/// imply that the atom is serializable.
|
||||
pub drop: Option<AtomId>,
|
||||
/// Data stored in the atom. This could be a key into a map, or the raw data
|
||||
/// of the atom if it isn't too big.
|
||||
pub data: AtomData,
|
||||
/// Instance ID of the system that created the atom
|
||||
pub owner: SysId,
|
||||
/// Indicates how the owner should be notified when this atom is dropped.
|
||||
/// Construction is always explicit and atoms are never cloned.
|
||||
///
|
||||
/// Atoms with `drop == None` are also known as trivial, they can be
|
||||
/// duplicated and stored with no regard to expression lifetimes. NOTICE
|
||||
/// that this only applies to the atom. If it's referenced with an
|
||||
/// [ExprTicket], the ticket itself can still expire.
|
||||
///
|
||||
/// Notice also that the atoms still expire when the system is dropped, and
|
||||
/// are not portable across instances of the same system, so this doesn't
|
||||
/// imply that the atom is serializable.
|
||||
pub drop: Option<AtomId>,
|
||||
/// Data stored in the atom. This could be a key into a map, or the raw data
|
||||
/// of the atom if it isn't too big.
|
||||
pub data: AtomData,
|
||||
}
|
||||
|
||||
/// Attempt to apply an atom as a function to an expression
|
||||
@@ -50,7 +52,7 @@ pub struct Atom {
|
||||
#[extends(AtomReq, HostExtReq)]
|
||||
pub struct CallRef(pub Atom, pub ExprTicket);
|
||||
impl Request for CallRef {
|
||||
type Response = Expression;
|
||||
type Response = Expression;
|
||||
}
|
||||
|
||||
/// Attempt to apply an atom as a function, consuming the atom and enabling the
|
||||
@@ -60,21 +62,21 @@ impl Request for CallRef {
|
||||
#[extends(AtomReq, HostExtReq)]
|
||||
pub struct FinalCall(pub Atom, pub ExprTicket);
|
||||
impl Request for FinalCall {
|
||||
type Response = Expression;
|
||||
type Response = Expression;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(AtomReq, HostExtReq)]
|
||||
pub struct SerializeAtom(pub Atom);
|
||||
impl Request for SerializeAtom {
|
||||
type Response = Option<(Vec<u8>, Vec<ExprTicket>)>;
|
||||
type Response = Option<(Vec<u8>, Vec<ExprTicket>)>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(HostExtReq)]
|
||||
pub struct DeserAtom(pub SysId, pub Vec<u8>, pub Vec<ExprTicket>);
|
||||
impl Request for DeserAtom {
|
||||
type Response = Atom;
|
||||
type Response = Atom;
|
||||
}
|
||||
|
||||
/// A request blindly routed to the system that provides an atom.
|
||||
@@ -82,26 +84,26 @@ impl Request for DeserAtom {
|
||||
#[extends(AtomReq, HostExtReq)]
|
||||
pub struct Fwded(pub Atom, pub TStrv, pub Vec<u8>);
|
||||
impl Request for Fwded {
|
||||
type Response = Option<Vec<u8>>;
|
||||
type Response = Option<Vec<u8>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(ExtHostReq)]
|
||||
pub struct Fwd(pub Atom, pub TStrv, pub Vec<u8>);
|
||||
impl Request for Fwd {
|
||||
type Response = Option<Vec<u8>>;
|
||||
type Response = Option<Vec<u8>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum NextStep {
|
||||
Continue(Expression),
|
||||
Halt,
|
||||
Continue(Expression),
|
||||
Halt,
|
||||
}
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(AtomReq, HostExtReq)]
|
||||
pub struct Command(pub Atom);
|
||||
impl Request for Command {
|
||||
type Response = OrcResult<NextStep>;
|
||||
type Response = OrcResult<NextStep>;
|
||||
}
|
||||
|
||||
/// Notification that an atom is being dropped because its associated expression
|
||||
@@ -115,7 +117,7 @@ pub struct AtomDrop(pub SysId, pub AtomId);
|
||||
#[extends(AtomReq, HostExtReq)]
|
||||
pub struct AtomPrint(pub Atom);
|
||||
impl Request for AtomPrint {
|
||||
type Response = String;
|
||||
type Response = String;
|
||||
}
|
||||
|
||||
/// Requests that apply to an existing atom instance
|
||||
@@ -123,24 +125,24 @@ impl Request for AtomPrint {
|
||||
#[extends(HostExtReq)]
|
||||
#[extendable]
|
||||
pub enum AtomReq {
|
||||
CallRef(CallRef),
|
||||
FinalCall(FinalCall),
|
||||
Fwded(Fwded),
|
||||
Command(Command),
|
||||
AtomPrint(AtomPrint),
|
||||
SerializeAtom(SerializeAtom),
|
||||
CallRef(CallRef),
|
||||
FinalCall(FinalCall),
|
||||
Fwded(Fwded),
|
||||
Command(Command),
|
||||
AtomPrint(AtomPrint),
|
||||
SerializeAtom(SerializeAtom),
|
||||
}
|
||||
impl AtomReq {
|
||||
/// Obtain the first [Atom] argument of the request. All requests in this
|
||||
/// subclass have at least one atom argument.
|
||||
pub fn get_atom(&self) -> &Atom {
|
||||
match self {
|
||||
Self::CallRef(CallRef(a, ..))
|
||||
| Self::Command(Command(a))
|
||||
| Self::FinalCall(FinalCall(a, ..))
|
||||
| Self::Fwded(Fwded(a, ..))
|
||||
| Self::AtomPrint(AtomPrint(a))
|
||||
| Self::SerializeAtom(SerializeAtom(a)) => a,
|
||||
}
|
||||
}
|
||||
/// Obtain the first [Atom] argument of the request. All requests in this
|
||||
/// subclass have at least one atom argument.
|
||||
pub fn get_atom(&self) -> &Atom {
|
||||
match self {
|
||||
Self::CallRef(CallRef(a, ..))
|
||||
| Self::Command(Command(a))
|
||||
| Self::FinalCall(FinalCall(a, ..))
|
||||
| Self::Fwded(Fwded(a, ..))
|
||||
| Self::AtomPrint(AtomPrint(a))
|
||||
| Self::SerializeAtom(SerializeAtom(a)) => a,
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-13
@@ -10,11 +10,11 @@ pub struct ErrId(pub NonZeroU16);
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct ErrLocation {
|
||||
/// Description of the relation of this location to the error. If not used,
|
||||
/// set to empty string
|
||||
pub message: Arc<String>,
|
||||
/// Location in code where the error emerged. This is usually [Location::Gen].
|
||||
pub location: Location,
|
||||
/// Description of the relation of this location to the error. If not used,
|
||||
/// set to empty string
|
||||
pub message: Arc<String>,
|
||||
/// Location in code where the error emerged. This is usually [Location::Gen].
|
||||
pub location: Location,
|
||||
}
|
||||
|
||||
/// Programming errors raised by extensions. At runtime these produce the
|
||||
@@ -24,14 +24,14 @@ pub struct ErrLocation {
|
||||
/// and a bottom if the file name isn't a string.
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct OrcError {
|
||||
/// General description of the kind of error.
|
||||
pub description: TStr,
|
||||
/// Specific information about the exact error, preferably containing concrete
|
||||
/// values.
|
||||
pub message: Arc<String>,
|
||||
/// Specific code fragments that have contributed to the emergence of the
|
||||
/// error.
|
||||
pub locations: Vec<ErrLocation>,
|
||||
/// General description of the kind of error.
|
||||
pub description: TStr,
|
||||
/// Specific information about the exact error, preferably containing concrete
|
||||
/// values.
|
||||
pub message: Arc<String>,
|
||||
/// Specific code fragments that have contributed to the emergence of the
|
||||
/// error.
|
||||
pub locations: Vec<ErrLocation>,
|
||||
}
|
||||
|
||||
/// If this is an [`Err`] then the [`Vec`] must not be empty.
|
||||
|
||||
+39
-39
@@ -43,9 +43,9 @@ pub struct Release(pub SysId, pub ExprTicket);
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(ExprNotif, ExtHostNotif)]
|
||||
pub struct Move {
|
||||
pub dec: SysId,
|
||||
pub inc: SysId,
|
||||
pub expr: ExprTicket,
|
||||
pub dec: SysId,
|
||||
pub inc: SysId,
|
||||
pub expr: ExprTicket,
|
||||
}
|
||||
|
||||
/// A description of a new expression. It is used as the return value of
|
||||
@@ -53,48 +53,48 @@ pub struct Move {
|
||||
/// [crate::tree::Tree].
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum ExpressionKind {
|
||||
/// Apply the lhs as a function to the rhs
|
||||
Call(Box<Expression>, Box<Expression>),
|
||||
/// Lambda function. The number operates as an argument name
|
||||
Lambda(u64, Box<Expression>),
|
||||
/// Binds the argument passed to the lambda with the same ID in the same
|
||||
/// template
|
||||
Arg(u64),
|
||||
/// Insert the specified host-expression in the template here. When the clause
|
||||
/// is used in the const tree, this variant is forbidden.
|
||||
Slot(ExprTicket),
|
||||
/// The lhs must be fully processed before the rhs can be processed.
|
||||
/// Equivalent to Haskell's function of the same name
|
||||
Seq(Box<Expression>, Box<Expression>),
|
||||
/// Insert a new atom in the tree. When the clause is used in the const tree,
|
||||
/// the atom must be trivial. This is always a newly constructed atom, if you
|
||||
/// want to reference an existing atom, use the corresponding [ExprTicket].
|
||||
/// Because the atom is newly constructed, it also must belong to this system.
|
||||
NewAtom(Atom),
|
||||
/// A reference to a constant
|
||||
Const(TStrv),
|
||||
/// A static runtime error.
|
||||
Bottom(Vec<OrcError>),
|
||||
/// Apply the lhs as a function to the rhs
|
||||
Call(Box<Expression>, Box<Expression>),
|
||||
/// Lambda function. The number operates as an argument name
|
||||
Lambda(u64, Box<Expression>),
|
||||
/// Binds the argument passed to the lambda with the same ID in the same
|
||||
/// template
|
||||
Arg(u64),
|
||||
/// Insert the specified host-expression in the template here. When the clause
|
||||
/// is used in the const tree, this variant is forbidden.
|
||||
Slot(ExprTicket),
|
||||
/// The lhs must be fully processed before the rhs can be processed.
|
||||
/// Equivalent to Haskell's function of the same name
|
||||
Seq(Box<Expression>, Box<Expression>),
|
||||
/// Insert a new atom in the tree. When the clause is used in the const tree,
|
||||
/// the atom must be trivial. This is always a newly constructed atom, if you
|
||||
/// want to reference an existing atom, use the corresponding [ExprTicket].
|
||||
/// Because the atom is newly constructed, it also must belong to this system.
|
||||
NewAtom(Atom),
|
||||
/// A reference to a constant
|
||||
Const(TStrv),
|
||||
/// A static runtime error.
|
||||
Bottom(Vec<OrcError>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Expression {
|
||||
pub kind: ExpressionKind,
|
||||
pub location: Location,
|
||||
pub kind: ExpressionKind,
|
||||
pub location: Location,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum InspectedKind {
|
||||
Atom(Atom),
|
||||
Bottom(Vec<OrcError>),
|
||||
Opaque,
|
||||
Atom(Atom),
|
||||
Bottom(Vec<OrcError>),
|
||||
Opaque,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Inspected {
|
||||
pub kind: InspectedKind,
|
||||
pub location: Location,
|
||||
pub refcount: u32,
|
||||
pub kind: InspectedKind,
|
||||
pub location: Location,
|
||||
pub refcount: u32,
|
||||
}
|
||||
|
||||
/// Obtain information about an expression. Used to act upon arguments by
|
||||
@@ -103,24 +103,24 @@ pub struct Inspected {
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(ExprReq, ExtHostReq)]
|
||||
pub struct Inspect {
|
||||
pub target: ExprTicket,
|
||||
pub target: ExprTicket,
|
||||
}
|
||||
impl Request for Inspect {
|
||||
type Response = Inspected;
|
||||
type Response = Inspected;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(ExtHostReq)]
|
||||
#[extendable]
|
||||
pub enum ExprReq {
|
||||
Inspect(Inspect),
|
||||
Inspect(Inspect),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(ExtHostNotif)]
|
||||
#[extendable]
|
||||
pub enum ExprNotif {
|
||||
Acquire(Acquire),
|
||||
Release(Release),
|
||||
Move(Move),
|
||||
Acquire(Acquire),
|
||||
Release(Release),
|
||||
Move(Move),
|
||||
}
|
||||
+11
-11
@@ -12,10 +12,10 @@ use crate::{ExtHostReq, HostExtReq};
|
||||
#[extends(ExtHostReq)]
|
||||
#[extendable]
|
||||
pub enum IntReq {
|
||||
InternStr(InternStr),
|
||||
InternStrv(InternStrv),
|
||||
ExternStr(ExternStr),
|
||||
ExternStrv(ExternStrv),
|
||||
InternStr(InternStr),
|
||||
InternStrv(InternStrv),
|
||||
ExternStr(ExternStr),
|
||||
ExternStrv(ExternStrv),
|
||||
}
|
||||
|
||||
/// replica -> master to intern a string on the master. Repeatable.
|
||||
@@ -25,7 +25,7 @@ pub enum IntReq {
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct InternStr(pub Arc<String>);
|
||||
impl Request for InternStr {
|
||||
type Response = TStr;
|
||||
type Response = TStr;
|
||||
}
|
||||
|
||||
/// replica -> master to find the interned string corresponding to a key.
|
||||
@@ -37,7 +37,7 @@ impl Request for InternStr {
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct ExternStr(pub TStr);
|
||||
impl Request for ExternStr {
|
||||
type Response = Arc<String>;
|
||||
type Response = Arc<String>;
|
||||
}
|
||||
/// replica -> master to intern a vector of interned strings
|
||||
///
|
||||
@@ -48,7 +48,7 @@ impl Request for ExternStr {
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct InternStrv(pub Arc<Vec<TStr>>);
|
||||
impl Request for InternStrv {
|
||||
type Response = TStrv;
|
||||
type Response = TStrv;
|
||||
}
|
||||
/// replica -> master to find the vector of interned strings corresponding to a
|
||||
/// token
|
||||
@@ -60,7 +60,7 @@ impl Request for InternStrv {
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct ExternStrv(pub TStrv);
|
||||
impl Request for ExternStrv {
|
||||
type Response = Arc<Vec<TStr>>;
|
||||
type Response = Arc<Vec<TStr>>;
|
||||
}
|
||||
|
||||
/// A substitute for an interned string in serialized datastructures.
|
||||
@@ -77,13 +77,13 @@ pub struct TStrv(pub NonZeroU64);
|
||||
#[extends(HostExtReq)]
|
||||
pub struct Sweep;
|
||||
impl Request for Sweep {
|
||||
type Response = Retained;
|
||||
type Response = Retained;
|
||||
}
|
||||
|
||||
/// List of keys in this replica that couldn't be sweeped because local
|
||||
/// datastructures reference their value.
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Retained {
|
||||
pub strings: Vec<TStr>,
|
||||
pub vecs: Vec<TStrv>,
|
||||
pub strings: Vec<TStr>,
|
||||
pub vecs: Vec<TStrv>,
|
||||
}
|
||||
+12
-12
@@ -14,33 +14,33 @@ pub struct CharFilter(pub Vec<RangeInclusive<char>>);
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(HostExtReq)]
|
||||
pub struct LexExpr {
|
||||
pub sys: SysId,
|
||||
pub id: ParsId,
|
||||
pub text: TStr,
|
||||
pub pos: u32,
|
||||
pub sys: SysId,
|
||||
pub id: ParsId,
|
||||
pub text: TStr,
|
||||
pub pos: u32,
|
||||
}
|
||||
impl Request for LexExpr {
|
||||
type Response = Option<OrcResult<LexedExpr>>;
|
||||
type Response = Option<OrcResult<LexedExpr>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct LexedExpr {
|
||||
pub pos: u32,
|
||||
pub expr: TokenTree,
|
||||
pub pos: u32,
|
||||
pub expr: TokenTree,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(ExtHostReq)]
|
||||
pub struct SubLex {
|
||||
pub id: ParsId,
|
||||
pub pos: u32,
|
||||
pub id: ParsId,
|
||||
pub pos: u32,
|
||||
}
|
||||
impl Request for SubLex {
|
||||
type Response = Option<SubLexed>;
|
||||
type Response = Option<SubLexed>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct SubLexed {
|
||||
pub pos: u32,
|
||||
pub ticket: TreeTicket,
|
||||
pub pos: u32,
|
||||
pub ticket: TreeTicket,
|
||||
}
|
||||
+17
-17
@@ -6,29 +6,29 @@ use crate::{TStr, TStrv};
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum Location {
|
||||
/// Location inaccessible. Locations are always debugging aids and never
|
||||
/// mandatory.
|
||||
None,
|
||||
/// Associated with a slot when wrapped in an expression.
|
||||
SlotTarget,
|
||||
/// Used in functions to denote the generated code that carries on the
|
||||
/// location of the call.
|
||||
Inherit,
|
||||
Gen(CodeGenInfo),
|
||||
/// Range and file
|
||||
SourceRange(SourceRange),
|
||||
/// Range only, file implied. Most notably used by parsers
|
||||
Range(Range<u32>),
|
||||
/// Location inaccessible. Locations are always debugging aids and never
|
||||
/// mandatory.
|
||||
None,
|
||||
/// Associated with a slot when wrapped in an expression.
|
||||
SlotTarget,
|
||||
/// Used in functions to denote the generated code that carries on the
|
||||
/// location of the call.
|
||||
Inherit,
|
||||
Gen(CodeGenInfo),
|
||||
/// Range and file
|
||||
SourceRange(SourceRange),
|
||||
/// Range only, file implied. Most notably used by parsers
|
||||
Range(Range<u32>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct SourceRange {
|
||||
pub path: TStrv,
|
||||
pub range: Range<u32>,
|
||||
pub path: TStrv,
|
||||
pub range: Range<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct CodeGenInfo {
|
||||
pub generator: TStrv,
|
||||
pub details: TStr,
|
||||
pub generator: TStrv,
|
||||
pub details: TStr,
|
||||
}
|
||||
@@ -4,8 +4,8 @@ use crate::ExtHostNotif;
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum LogStrategy {
|
||||
StdErr,
|
||||
File(String),
|
||||
StdErr,
|
||||
File(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
|
||||
+34
-31
@@ -5,79 +5,82 @@ use orchid_api_derive::{Coding, Hierarchy};
|
||||
use orchid_api_traits::Request;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use crate::{Atom, Comment, ExtHostReq, HostExtReq, Location, OrcResult, Paren, ParsId, SysId, TStr, TStrv};
|
||||
use crate::{
|
||||
Atom, Comment, ExtHostReq, HostExtReq, Location, OrcResult, Paren, ParsId, SysId, TStr, TStrv,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Coding, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct MacroTreeId(pub NonZeroU64);
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct MacroTree {
|
||||
pub location: Location,
|
||||
pub token: MacroToken,
|
||||
pub location: Location,
|
||||
pub token: MacroToken,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum MacroToken {
|
||||
S(Paren, Vec<MacroTree>),
|
||||
Name(TStrv),
|
||||
Slot(MacroTreeId),
|
||||
Lambda(Vec<MacroTree>, Vec<MacroTree>),
|
||||
Ph(Placeholder),
|
||||
Atom(Atom),
|
||||
S(Paren, Vec<MacroTree>),
|
||||
Name(TStrv),
|
||||
Slot(MacroTreeId),
|
||||
Lambda(Vec<MacroTree>, Vec<MacroTree>),
|
||||
Ph(Placeholder),
|
||||
Atom(Atom),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct MacroBlock {
|
||||
pub priority: Option<NotNan<f64>>,
|
||||
pub rules: Vec<MacroRule>,
|
||||
pub priority: Option<NotNan<f64>>,
|
||||
pub rules: Vec<MacroRule>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct MacroRule {
|
||||
pub location: Location,
|
||||
pub comments: Vec<Comment>,
|
||||
pub pattern: Vec<MacroTree>,
|
||||
pub id: MacroId,
|
||||
pub location: Location,
|
||||
pub comments: Vec<Comment>,
|
||||
pub pattern: Vec<MacroTree>,
|
||||
pub id: MacroId,
|
||||
}
|
||||
|
||||
/// A specific macro rule with a specific pattern across invocations
|
||||
#[derive(Clone, Copy, Debug, Coding, PartialEq, Eq, Hash)]
|
||||
pub struct MacroId(pub NonZeroU64);
|
||||
|
||||
/// After a pattern matches, this call executes the body of the macro. This request returns None
|
||||
/// if an inner nested request raised an exception
|
||||
/// After a pattern matches, this call executes the body of the macro. This
|
||||
/// request returns None if an inner nested request raised an exception
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(HostExtReq)]
|
||||
pub struct ApplyMacro {
|
||||
pub sys: SysId,
|
||||
pub id: MacroId,
|
||||
/// Recursion token
|
||||
pub run_id: ParsId,
|
||||
/// Must contain exactly the keys that were specified as placeholders in the pattern
|
||||
pub params: HashMap<TStr, Vec<MacroTree>>,
|
||||
pub sys: SysId,
|
||||
pub id: MacroId,
|
||||
/// Recursion token
|
||||
pub run_id: ParsId,
|
||||
/// Must contain exactly the keys that were specified as placeholders in the
|
||||
/// pattern
|
||||
pub params: HashMap<TStr, Vec<MacroTree>>,
|
||||
}
|
||||
impl Request for ApplyMacro {
|
||||
type Response = Option<OrcResult<Vec<MacroTree>>>;
|
||||
type Response = Option<OrcResult<Vec<MacroTree>>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(ExtHostReq)]
|
||||
pub struct RunMacros {
|
||||
pub run_id: ParsId,
|
||||
pub query: Vec<MacroTree>,
|
||||
pub run_id: ParsId,
|
||||
pub query: Vec<MacroTree>,
|
||||
}
|
||||
impl Request for RunMacros {
|
||||
type Response = Option<Vec<MacroTree>>;
|
||||
type Response = Option<Vec<MacroTree>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Placeholder {
|
||||
pub name: TStr,
|
||||
pub kind: PhKind,
|
||||
pub name: TStr,
|
||||
pub kind: PhKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Coding)]
|
||||
pub enum PhKind {
|
||||
Scalar,
|
||||
Vector { priority: u8, at_least_one: bool },
|
||||
Scalar,
|
||||
Vector { priority: u8, at_least_one: bool },
|
||||
}
|
||||
@@ -11,11 +11,11 @@ pub struct ParsId(pub NonZeroU64);
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(HostExtReq)]
|
||||
pub struct ParseLine {
|
||||
pub sys: SysId,
|
||||
pub comments: Vec<Comment>,
|
||||
pub exported: bool,
|
||||
pub line: Vec<TokenTree>,
|
||||
pub sys: SysId,
|
||||
pub comments: Vec<Comment>,
|
||||
pub exported: bool,
|
||||
pub line: Vec<TokenTree>,
|
||||
}
|
||||
impl Request for ParseLine {
|
||||
type Response = OrcResult<Vec<TokenTree>>;
|
||||
type Response = OrcResult<Vec<TokenTree>>;
|
||||
}
|
||||
+81
-81
@@ -25,63 +25,63 @@
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use orchid_api_derive::{Coding, Hierarchy};
|
||||
use orchid_api_traits::{read_exact, write_exact, Channel, Decode, Encode, MsgSet, Request};
|
||||
use orchid_api_traits::{Channel, Decode, Encode, MsgSet, Request, read_exact, write_exact};
|
||||
|
||||
use crate::{atom, expr, interner, lexer, logging, macros, parser, system, tree, vfs};
|
||||
|
||||
static HOST_INTRO: &[u8] = b"Orchid host, binary API v0\n";
|
||||
pub struct HostHeader {
|
||||
pub log_strategy: logging::LogStrategy,
|
||||
pub log_strategy: logging::LogStrategy,
|
||||
}
|
||||
impl Decode for HostHeader {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
read_exact(read, HOST_INTRO);
|
||||
Self { log_strategy: logging::LogStrategy::decode(read) }
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
read_exact(read, HOST_INTRO);
|
||||
Self { log_strategy: logging::LogStrategy::decode(read) }
|
||||
}
|
||||
}
|
||||
impl Encode for HostHeader {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write_exact(write, HOST_INTRO);
|
||||
self.log_strategy.encode(write)
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write_exact(write, HOST_INTRO);
|
||||
self.log_strategy.encode(write)
|
||||
}
|
||||
}
|
||||
|
||||
static EXT_INTRO: &[u8] = b"Orchid extension, binary API v0\n";
|
||||
pub struct ExtensionHeader {
|
||||
pub name: String,
|
||||
pub systems: Vec<system::SystemDecl>,
|
||||
pub name: String,
|
||||
pub systems: Vec<system::SystemDecl>,
|
||||
}
|
||||
impl Decode for ExtensionHeader {
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
read_exact(read, EXT_INTRO);
|
||||
Self { name: String::decode(read), systems: Vec::decode(read) }
|
||||
}
|
||||
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
|
||||
read_exact(read, EXT_INTRO);
|
||||
Self { name: String::decode(read), systems: Vec::decode(read) }
|
||||
}
|
||||
}
|
||||
impl Encode for ExtensionHeader {
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write_exact(write, EXT_INTRO);
|
||||
self.name.encode(write);
|
||||
self.systems.encode(write)
|
||||
}
|
||||
fn encode<W: Write + ?Sized>(&self, write: &mut W) {
|
||||
write_exact(write, EXT_INTRO);
|
||||
self.name.encode(write);
|
||||
self.systems.encode(write)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||
pub struct Ping;
|
||||
impl Request for Ping {
|
||||
type Response = ();
|
||||
type Response = ();
|
||||
}
|
||||
|
||||
/// Requests running from the extension to the host
|
||||
#[derive(Clone, Coding, Hierarchy)]
|
||||
#[extendable]
|
||||
pub enum ExtHostReq {
|
||||
Ping(Ping),
|
||||
IntReq(interner::IntReq),
|
||||
Fwd(atom::Fwd),
|
||||
SysFwd(system::SysFwd),
|
||||
ExprReq(expr::ExprReq),
|
||||
SubLex(lexer::SubLex),
|
||||
RunMacros(macros::RunMacros),
|
||||
Ping(Ping),
|
||||
IntReq(interner::IntReq),
|
||||
Fwd(atom::Fwd),
|
||||
SysFwd(system::SysFwd),
|
||||
ExprReq(expr::ExprReq),
|
||||
SubLex(lexer::SubLex),
|
||||
RunMacros(macros::RunMacros),
|
||||
}
|
||||
|
||||
/// Notifications sent from the extension to the host
|
||||
@@ -89,93 +89,93 @@ pub enum ExtHostReq {
|
||||
#[derive(Debug, Clone, Coding, Hierarchy)]
|
||||
#[extendable]
|
||||
pub enum ExtHostNotif {
|
||||
ExprNotif(expr::ExprNotif),
|
||||
Log(logging::Log),
|
||||
ExprNotif(expr::ExprNotif),
|
||||
Log(logging::Log),
|
||||
}
|
||||
|
||||
pub struct ExtHostChannel;
|
||||
impl Channel for ExtHostChannel {
|
||||
type Notif = ExtHostNotif;
|
||||
type Req = ExtHostReq;
|
||||
type Notif = ExtHostNotif;
|
||||
type Req = ExtHostReq;
|
||||
}
|
||||
|
||||
/// Requests running from the host to the extension
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extendable]
|
||||
pub enum HostExtReq {
|
||||
Ping(Ping),
|
||||
SysReq(system::SysReq),
|
||||
Sweep(interner::Sweep),
|
||||
AtomReq(atom::AtomReq),
|
||||
DeserAtom(atom::DeserAtom),
|
||||
LexExpr(lexer::LexExpr),
|
||||
ParseLine(parser::ParseLine),
|
||||
GetMember(tree::GetMember),
|
||||
VfsReq(vfs::VfsReq),
|
||||
ApplyMacro(macros::ApplyMacro),
|
||||
Ping(Ping),
|
||||
SysReq(system::SysReq),
|
||||
Sweep(interner::Sweep),
|
||||
AtomReq(atom::AtomReq),
|
||||
DeserAtom(atom::DeserAtom),
|
||||
LexExpr(lexer::LexExpr),
|
||||
ParseLine(parser::ParseLine),
|
||||
GetMember(tree::GetMember),
|
||||
VfsReq(vfs::VfsReq),
|
||||
ApplyMacro(macros::ApplyMacro),
|
||||
}
|
||||
|
||||
/// Notifications sent from the host to the extension
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extendable]
|
||||
pub enum HostExtNotif {
|
||||
SystemDrop(system::SystemDrop),
|
||||
AtomDrop(atom::AtomDrop),
|
||||
/// The host can assume that after this notif is sent, a correctly written
|
||||
/// extension will eventually exit.
|
||||
Exit,
|
||||
SystemDrop(system::SystemDrop),
|
||||
AtomDrop(atom::AtomDrop),
|
||||
/// The host can assume that after this notif is sent, a correctly written
|
||||
/// extension will eventually exit.
|
||||
Exit,
|
||||
}
|
||||
|
||||
pub struct HostExtChannel;
|
||||
impl Channel for HostExtChannel {
|
||||
type Notif = HostExtNotif;
|
||||
type Req = HostExtReq;
|
||||
type Notif = HostExtNotif;
|
||||
type Req = HostExtReq;
|
||||
}
|
||||
|
||||
/// Message set viewed from the extension's perspective
|
||||
pub struct ExtMsgSet;
|
||||
impl MsgSet for ExtMsgSet {
|
||||
type In = HostExtChannel;
|
||||
type Out = ExtHostChannel;
|
||||
type In = HostExtChannel;
|
||||
type Out = ExtHostChannel;
|
||||
}
|
||||
|
||||
/// Message Set viewed from the host's perspective
|
||||
pub struct HostMsgSet;
|
||||
impl MsgSet for HostMsgSet {
|
||||
type In = ExtHostChannel;
|
||||
type Out = HostExtChannel;
|
||||
type In = ExtHostChannel;
|
||||
type Out = HostExtChannel;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use orchid_api_traits::enc_vec;
|
||||
use ordered_float::NotNan;
|
||||
use orchid_api_traits::enc_vec;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn host_header_enc() {
|
||||
let hh = HostHeader { log_strategy: logging::LogStrategy::File("SomeFile".to_string()) };
|
||||
let mut enc = &enc_vec(&hh)[..];
|
||||
eprintln!("Encoded to {enc:?}");
|
||||
HostHeader::decode(&mut enc);
|
||||
assert_eq!(enc, []);
|
||||
}
|
||||
#[test]
|
||||
fn host_header_enc() {
|
||||
let hh = HostHeader { log_strategy: logging::LogStrategy::File("SomeFile".to_string()) };
|
||||
let mut enc = &enc_vec(&hh)[..];
|
||||
eprintln!("Encoded to {enc:?}");
|
||||
HostHeader::decode(&mut enc);
|
||||
assert_eq!(enc, []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ext_header_enc() {
|
||||
let eh = ExtensionHeader {
|
||||
name: "my_extension".to_string(),
|
||||
systems: vec![system::SystemDecl {
|
||||
id: system::SysDeclId(1.try_into().unwrap()),
|
||||
name: "misc".to_string(),
|
||||
depends: vec!["std".to_string()],
|
||||
priority: NotNan::new(1f64).unwrap(),
|
||||
}],
|
||||
};
|
||||
let mut enc = &enc_vec(&eh)[..];
|
||||
eprintln!("Encoded to {enc:?}");
|
||||
ExtensionHeader::decode(&mut enc);
|
||||
assert_eq!(enc, [])
|
||||
}
|
||||
#[test]
|
||||
fn ext_header_enc() {
|
||||
let eh = ExtensionHeader {
|
||||
name: "my_extension".to_string(),
|
||||
systems: vec![system::SystemDecl {
|
||||
id: system::SysDeclId(1.try_into().unwrap()),
|
||||
name: "misc".to_string(),
|
||||
depends: vec!["std".to_string()],
|
||||
priority: NotNan::new(1f64).unwrap(),
|
||||
}],
|
||||
};
|
||||
let mut enc = &enc_vec(&eh)[..];
|
||||
eprintln!("Encoded to {enc:?}");
|
||||
ExtensionHeader::decode(&mut enc);
|
||||
assert_eq!(enc, [])
|
||||
}
|
||||
}
|
||||
+33
-33
@@ -19,21 +19,21 @@ pub struct SysId(pub NonZeroU16);
|
||||
/// extension header, so it cannot rely on the interner.
|
||||
#[derive(Debug, Clone, Coding)]
|
||||
pub struct SystemDecl {
|
||||
/// ID of the system, unique within the library
|
||||
pub id: SysDeclId,
|
||||
/// This can be depended upon. Exactly one of each kind will be loaded
|
||||
pub name: String,
|
||||
/// If multiple instances of a system are found, the highest priority will be
|
||||
/// used. This can be used for version counting, but also for fallbacks if a
|
||||
/// negative number is found.
|
||||
///
|
||||
/// Systems cannot depend on specific versions and older versions of systems
|
||||
/// are never loaded. Compatibility can be determined on a per-system basis
|
||||
/// through an algorithm chosen by the provider.
|
||||
pub priority: NotNan<f64>,
|
||||
/// List of systems needed for this one to work correctly. These will be
|
||||
/// looked up, and an error produced if they aren't found.
|
||||
pub depends: Vec<String>,
|
||||
/// ID of the system, unique within the library
|
||||
pub id: SysDeclId,
|
||||
/// This can be depended upon. Exactly one of each kind will be loaded
|
||||
pub name: String,
|
||||
/// If multiple instances of a system are found, the highest priority will be
|
||||
/// used. This can be used for version counting, but also for fallbacks if a
|
||||
/// negative number is found.
|
||||
///
|
||||
/// Systems cannot depend on specific versions and older versions of systems
|
||||
/// are never loaded. Compatibility can be determined on a per-system basis
|
||||
/// through an algorithm chosen by the provider.
|
||||
pub priority: NotNan<f64>,
|
||||
/// List of systems needed for this one to work correctly. These will be
|
||||
/// looked up, and an error produced if they aren't found.
|
||||
pub depends: Vec<String>,
|
||||
}
|
||||
|
||||
/// Host -> extension; instantiate a system according to its [SystemDecl].
|
||||
@@ -43,26 +43,26 @@ pub struct SystemDecl {
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(SysReq, HostExtReq)]
|
||||
pub struct NewSystem {
|
||||
/// ID of the system
|
||||
pub system: SysDeclId,
|
||||
/// ID of the system instance, unique for the host
|
||||
pub id: SysId,
|
||||
/// Instance IDs for dependencies, in the order that the names appear in the
|
||||
/// declaration
|
||||
pub depends: Vec<SysId>,
|
||||
/// ID of the system
|
||||
pub system: SysDeclId,
|
||||
/// ID of the system instance, unique for the host
|
||||
pub id: SysId,
|
||||
/// Instance IDs for dependencies, in the order that the names appear in the
|
||||
/// declaration
|
||||
pub depends: Vec<SysId>,
|
||||
}
|
||||
impl Request for NewSystem {
|
||||
type Response = SystemInst;
|
||||
type Response = SystemInst;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct SystemInst {
|
||||
/// The set of possible starting characters of tokens the lexer of this system
|
||||
/// can process. The lexer will notify this system if it encounters one of
|
||||
/// these characters.9
|
||||
pub lex_filter: CharFilter,
|
||||
pub line_types: Vec<TStr>,
|
||||
pub const_root: HashMap<TStr, MemberKind>,
|
||||
/// The set of possible starting characters of tokens the lexer of this system
|
||||
/// can process. The lexer will notify this system if it encounters one of
|
||||
/// these characters.9
|
||||
pub lex_filter: CharFilter,
|
||||
pub line_types: Vec<TStr>,
|
||||
pub const_root: HashMap<TStr, MemberKind>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
@@ -73,20 +73,20 @@ pub struct SystemDrop(pub SysId);
|
||||
#[extends(SysReq, HostExtReq)]
|
||||
pub struct SysFwded(pub SysId, pub Vec<u8>);
|
||||
impl Request for SysFwded {
|
||||
type Response = Vec<u8>;
|
||||
type Response = Vec<u8>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(ExtHostReq)]
|
||||
pub struct SysFwd(pub SysId, pub Vec<u8>);
|
||||
impl Request for SysFwd {
|
||||
type Response = Vec<u8>;
|
||||
type Response = Vec<u8>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(HostExtReq)]
|
||||
#[extendable]
|
||||
pub enum SysReq {
|
||||
NewSystem(NewSystem),
|
||||
SysFwded(SysFwded),
|
||||
NewSystem(NewSystem),
|
||||
SysFwded(SysFwded),
|
||||
}
|
||||
+45
-45
@@ -7,7 +7,7 @@ use orchid_api_traits::Request;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use crate::{
|
||||
Atom, Expression, HostExtReq, Location, MacroBlock, OrcError, Placeholder, SysId, TStr, TStrv,
|
||||
Atom, Expression, HostExtReq, Location, MacroBlock, OrcError, Placeholder, SysId, TStr, TStrv,
|
||||
};
|
||||
|
||||
/// A token tree from a lexer recursion request. Its lifetime is the lex call,
|
||||
@@ -22,42 +22,42 @@ pub struct TreeTicket(pub NonZeroU64);
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct TokenTree {
|
||||
pub token: Token,
|
||||
pub range: Range<u32>,
|
||||
pub token: Token,
|
||||
pub range: Range<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum Token {
|
||||
/// Lambda function head, from the opening \ until the beginning of the body.
|
||||
LambdaHead(Vec<TokenTree>),
|
||||
/// A name segment or an operator.
|
||||
Name(TStr),
|
||||
/// ::
|
||||
NS,
|
||||
/// Line break.
|
||||
BR,
|
||||
/// ( Round parens ), [ Square brackets ] or { Curly braces }
|
||||
S(Paren, Vec<TokenTree>),
|
||||
/// A new atom
|
||||
Atom(Atom),
|
||||
/// Anchor to insert a subtree
|
||||
Slot(TreeTicket),
|
||||
/// A static compile-time error returned by failing lexers if
|
||||
/// the rest of the source is likely still meaningful
|
||||
Bottom(Vec<OrcError>),
|
||||
/// A comment
|
||||
Comment(Arc<String>),
|
||||
/// Placeholder
|
||||
Ph(Placeholder),
|
||||
/// Macro block head
|
||||
Macro(Option<NotNan<f64>>),
|
||||
/// Lambda function head, from the opening \ until the beginning of the body.
|
||||
LambdaHead(Vec<TokenTree>),
|
||||
/// A name segment or an operator.
|
||||
Name(TStr),
|
||||
/// ::
|
||||
NS,
|
||||
/// Line break.
|
||||
BR,
|
||||
/// ( Round parens ), [ Square brackets ] or { Curly braces }
|
||||
S(Paren, Vec<TokenTree>),
|
||||
/// A new atom
|
||||
Atom(Atom),
|
||||
/// Anchor to insert a subtree
|
||||
Slot(TreeTicket),
|
||||
/// A static compile-time error returned by failing lexers if
|
||||
/// the rest of the source is likely still meaningful
|
||||
Bottom(Vec<OrcError>),
|
||||
/// A comment
|
||||
Comment(Arc<String>),
|
||||
/// Placeholder
|
||||
Ph(Placeholder),
|
||||
/// Macro block head
|
||||
Macro(Option<NotNan<f64>>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Coding)]
|
||||
pub enum Paren {
|
||||
Round,
|
||||
Square,
|
||||
Curly,
|
||||
Round,
|
||||
Square,
|
||||
Curly,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||
@@ -65,46 +65,46 @@ pub struct TreeId(pub NonZeroU64);
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Item {
|
||||
pub location: Location,
|
||||
pub comments: Vec<Comment>,
|
||||
pub kind: ItemKind,
|
||||
pub location: Location,
|
||||
pub comments: Vec<Comment>,
|
||||
pub kind: ItemKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum ItemKind {
|
||||
Member(Member),
|
||||
Macro(MacroBlock),
|
||||
Export(TStr),
|
||||
Import(TStrv),
|
||||
Member(Member),
|
||||
Macro(MacroBlock),
|
||||
Export(TStr),
|
||||
Import(TStrv),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Comment {
|
||||
pub text: TStr,
|
||||
pub location: Location,
|
||||
pub text: TStr,
|
||||
pub location: Location,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Member {
|
||||
pub name: TStr,
|
||||
pub kind: MemberKind,
|
||||
pub name: TStr,
|
||||
pub kind: MemberKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum MemberKind {
|
||||
Const(Expression),
|
||||
Module(Module),
|
||||
Lazy(TreeId),
|
||||
Const(Expression),
|
||||
Module(Module),
|
||||
Lazy(TreeId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Module {
|
||||
pub items: Vec<Item>,
|
||||
pub items: Vec<Item>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Coding, Hierarchy)]
|
||||
#[extends(HostExtReq)]
|
||||
pub struct GetMember(pub SysId, pub TreeId);
|
||||
impl Request for GetMember {
|
||||
type Response = MemberKind;
|
||||
type Response = MemberKind;
|
||||
}
|
||||
@@ -14,34 +14,34 @@ pub struct VfsId(pub NonZeroU16);
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum Loaded {
|
||||
Code(String),
|
||||
Collection(Vec<TStr>),
|
||||
Code(String),
|
||||
Collection(Vec<TStr>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(VfsReq, HostExtReq)]
|
||||
pub struct VfsRead(pub SysId, pub VfsId, pub Vec<TStr>);
|
||||
impl Request for VfsRead {
|
||||
type Response = OrcResult<Loaded>;
|
||||
type Response = OrcResult<Loaded>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub enum EagerVfs {
|
||||
Lazy(VfsId),
|
||||
Eager(HashMap<TStr, EagerVfs>),
|
||||
Lazy(VfsId),
|
||||
Eager(HashMap<TStr, EagerVfs>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(VfsReq, HostExtReq)]
|
||||
pub struct GetVfs(pub SysId);
|
||||
impl Request for GetVfs {
|
||||
type Response = EagerVfs;
|
||||
type Response = EagerVfs;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(HostExtReq)]
|
||||
#[extendable]
|
||||
pub enum VfsReq {
|
||||
GetVfs(GetVfs),
|
||||
VfsRead(VfsRead),
|
||||
GetVfs(GetVfs),
|
||||
VfsRead(VfsRead),
|
||||
}
|
||||
@@ -10,14 +10,14 @@ derive_destructure = "1.0.0"
|
||||
dyn-clone = "1.0.17"
|
||||
hashbrown = "0.15.2"
|
||||
itertools = "0.14.0"
|
||||
lazy_static = "1.4.0"
|
||||
lazy_static = "1.5.0"
|
||||
never = "0.1.0"
|
||||
num-traits = "0.2.19"
|
||||
orchid-api = { version = "0.1.0", path = "../orchid-api" }
|
||||
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
|
||||
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||
ordered-float = "4.2.0"
|
||||
rust-embed = "8.3.0"
|
||||
rust_decimal = "1.35.0"
|
||||
substack = "1.1.0"
|
||||
ordered-float = "4.6.0"
|
||||
rust-embed = "8.5.0"
|
||||
rust_decimal = "1.36.0"
|
||||
substack = "1.1.1"
|
||||
trait-set = "0.3.0"
|
||||
+16
-16
@@ -3,27 +3,27 @@ use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub enum ArcCow<'a, T: ?Sized + ToOwned> {
|
||||
Borrowed(&'a T),
|
||||
Owned(Arc<T::Owned>),
|
||||
Borrowed(&'a T),
|
||||
Owned(Arc<T::Owned>),
|
||||
}
|
||||
impl<T: ?Sized + ToOwned> ArcCow<'_, T> {
|
||||
pub fn owned(value: T::Owned) -> Self { Self::Owned(Arc::new(value)) }
|
||||
pub fn owned(value: T::Owned) -> Self { Self::Owned(Arc::new(value)) }
|
||||
}
|
||||
impl<T: ?Sized + ToOwned> Clone for ArcCow<'_, T> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Borrowed(r) => Self::Borrowed(r),
|
||||
Self::Owned(b) => Self::Owned(b.clone()),
|
||||
}
|
||||
}
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Borrowed(r) => Self::Borrowed(r),
|
||||
Self::Owned(b) => Self::Owned(b.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + ToOwned> Deref for ArcCow<'_, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Borrowed(t) => t,
|
||||
Self::Owned(b) => b.as_ref().borrow(),
|
||||
}
|
||||
}
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Borrowed(t) => t,
|
||||
Self::Owned(b) => b.as_ref().borrow(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,54 +8,54 @@ use crate::api;
|
||||
pub type CRange = RangeInclusive<char>;
|
||||
|
||||
pub trait ICFilter: fmt::Debug {
|
||||
fn ranges(&self) -> &[RangeInclusive<char>];
|
||||
fn ranges(&self) -> &[RangeInclusive<char>];
|
||||
}
|
||||
impl ICFilter for [RangeInclusive<char>] {
|
||||
fn ranges(&self) -> &[RangeInclusive<char>] { self }
|
||||
fn ranges(&self) -> &[RangeInclusive<char>] { self }
|
||||
}
|
||||
impl ICFilter for api::CharFilter {
|
||||
fn ranges(&self) -> &[RangeInclusive<char>] { &self.0 }
|
||||
fn ranges(&self) -> &[RangeInclusive<char>] { &self.0 }
|
||||
}
|
||||
|
||||
fn try_merge_char_ranges(left: CRange, right: CRange) -> Result<CRange, (CRange, CRange)> {
|
||||
match *left.end() as u32 + 1 < *right.start() as u32 {
|
||||
true => Err((left, right)),
|
||||
false => Ok(*left.start()..=*right.end()),
|
||||
}
|
||||
match *left.end() as u32 + 1 < *right.start() as u32 {
|
||||
true => Err((left, right)),
|
||||
false => Ok(*left.start()..=*right.end()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Process the character ranges to make them adhere to the structural
|
||||
/// requirements of [CharFilter]
|
||||
pub fn mk_char_filter(items: impl IntoIterator<Item = CRange>) -> api::CharFilter {
|
||||
api::CharFilter(
|
||||
(items.into_iter())
|
||||
.filter(|r| *r.start() as u32 <= *r.end() as u32)
|
||||
.sorted_by_key(|r| *r.start() as u32)
|
||||
.coalesce(try_merge_char_ranges)
|
||||
.collect_vec(),
|
||||
)
|
||||
api::CharFilter(
|
||||
(items.into_iter())
|
||||
.filter(|r| *r.start() as u32 <= *r.end() as u32)
|
||||
.sorted_by_key(|r| *r.start() as u32)
|
||||
.coalesce(try_merge_char_ranges)
|
||||
.collect_vec(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Decide whether a char filter matches a character via binary search
|
||||
pub fn char_filter_match(cf: &(impl ICFilter + ?Sized), c: char) -> bool {
|
||||
match cf.ranges().binary_search_by_key(&c, |l| *l.end()) {
|
||||
Ok(_) => true, // c is the end of a range
|
||||
Err(i) if i == cf.ranges().len() => false, // all ranges end before c
|
||||
Err(i) => cf.ranges()[i].contains(&c), /* c between cf.0[i-1]?.end and cf.0[i].end,
|
||||
* check [i] */
|
||||
}
|
||||
match cf.ranges().binary_search_by_key(&c, |l| *l.end()) {
|
||||
Ok(_) => true, // c is the end of a range
|
||||
Err(i) if i == cf.ranges().len() => false, // all ranges end before c
|
||||
Err(i) => cf.ranges()[i].contains(&c), /* c between cf.0[i-1]?.end and cf.0[i].end,
|
||||
* check [i] */
|
||||
}
|
||||
}
|
||||
|
||||
/// Merge two char filters into a filter that matches if either of the
|
||||
/// constituents would match.
|
||||
pub fn char_filter_union(
|
||||
l: &(impl ICFilter + ?Sized),
|
||||
r: &(impl ICFilter + ?Sized),
|
||||
l: &(impl ICFilter + ?Sized),
|
||||
r: &(impl ICFilter + ?Sized),
|
||||
) -> api::CharFilter {
|
||||
api::CharFilter(
|
||||
(l.ranges().iter().merge_by(r.ranges(), |l, r| l.start() <= r.start()))
|
||||
.cloned()
|
||||
.coalesce(try_merge_char_ranges)
|
||||
.collect_vec(),
|
||||
)
|
||||
api::CharFilter(
|
||||
(l.ranges().iter().merge_by(r.ranges(), |l, r| l.start() <= r.start()))
|
||||
.cloned()
|
||||
.coalesce(try_merge_char_ranges)
|
||||
.collect_vec(),
|
||||
)
|
||||
}
|
||||
@@ -6,19 +6,19 @@ use never::Never;
|
||||
/// variety of types for different purposes. Very broadly, if the operation
|
||||
/// succeeds, the result should represent _both_ inputs.
|
||||
pub trait Combine: Sized {
|
||||
/// Information about the failure
|
||||
type Error;
|
||||
/// Information about the failure
|
||||
type Error;
|
||||
|
||||
/// Merge two values into a value that represents both, if this is possible.
|
||||
fn combine(self, other: Self) -> Result<Self, Self::Error>;
|
||||
/// Merge two values into a value that represents both, if this is possible.
|
||||
fn combine(self, other: Self) -> Result<Self, Self::Error>;
|
||||
}
|
||||
|
||||
impl Combine for Never {
|
||||
type Error = Never;
|
||||
fn combine(self, _: Self) -> Result<Self, Self::Error> { match self {} }
|
||||
type Error = Never;
|
||||
fn combine(self, _: Self) -> Result<Self, Self::Error> { match self {} }
|
||||
}
|
||||
|
||||
impl Combine for () {
|
||||
type Error = Never;
|
||||
fn combine(self, (): Self) -> Result<Self, Self::Error> { Ok(()) }
|
||||
type Error = Never;
|
||||
fn combine(self, (): Self) -> Result<Self, Self::Error> { Ok(()) }
|
||||
}
|
||||
+102
-102
@@ -12,158 +12,158 @@ use crate::location::Pos;
|
||||
/// processing got stuck, a command that is likely to be incorrect
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ErrPos {
|
||||
/// The suspected origin
|
||||
pub position: Pos,
|
||||
/// Any information about the role of this origin
|
||||
pub message: Option<Arc<String>>,
|
||||
/// The suspected origin
|
||||
pub position: Pos,
|
||||
/// Any information about the role of this origin
|
||||
pub message: Option<Arc<String>>,
|
||||
}
|
||||
impl ErrPos {
|
||||
pub fn new(msg: &str, position: Pos) -> Self {
|
||||
Self { message: Some(Arc::new(msg.to_string())), position }
|
||||
}
|
||||
fn from_api(api: &api::ErrLocation) -> Self {
|
||||
Self {
|
||||
message: Some(api.message.clone()).filter(|s| !s.is_empty()),
|
||||
position: Pos::from_api(&api.location),
|
||||
}
|
||||
}
|
||||
fn to_api(&self) -> api::ErrLocation {
|
||||
api::ErrLocation {
|
||||
message: self.message.clone().unwrap_or_default(),
|
||||
location: self.position.to_api(),
|
||||
}
|
||||
}
|
||||
pub fn new(msg: &str, position: Pos) -> Self {
|
||||
Self { message: Some(Arc::new(msg.to_string())), position }
|
||||
}
|
||||
fn from_api(api: &api::ErrLocation) -> Self {
|
||||
Self {
|
||||
message: Some(api.message.clone()).filter(|s| !s.is_empty()),
|
||||
position: Pos::from_api(&api.location),
|
||||
}
|
||||
}
|
||||
fn to_api(&self) -> api::ErrLocation {
|
||||
api::ErrLocation {
|
||||
message: self.message.clone().unwrap_or_default(),
|
||||
location: self.position.to_api(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<Pos> for ErrPos {
|
||||
fn from(origin: Pos) -> Self { Self { position: origin, message: None } }
|
||||
fn from(origin: Pos) -> Self { Self { position: origin, message: None } }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OrcErr {
|
||||
pub description: Tok<String>,
|
||||
pub message: Arc<String>,
|
||||
pub positions: Vec<ErrPos>,
|
||||
pub description: Tok<String>,
|
||||
pub message: Arc<String>,
|
||||
pub positions: Vec<ErrPos>,
|
||||
}
|
||||
impl OrcErr {
|
||||
fn to_api(&self) -> api::OrcError {
|
||||
api::OrcError {
|
||||
description: self.description.to_api(),
|
||||
message: self.message.clone(),
|
||||
locations: self.positions.iter().map(ErrPos::to_api).collect(),
|
||||
}
|
||||
}
|
||||
fn from_api(api: &api::OrcError) -> Self {
|
||||
Self {
|
||||
description: Tok::from_api(api.description),
|
||||
message: api.message.clone(),
|
||||
positions: api.locations.iter().map(ErrPos::from_api).collect(),
|
||||
}
|
||||
}
|
||||
fn to_api(&self) -> api::OrcError {
|
||||
api::OrcError {
|
||||
description: self.description.to_api(),
|
||||
message: self.message.clone(),
|
||||
locations: self.positions.iter().map(ErrPos::to_api).collect(),
|
||||
}
|
||||
}
|
||||
fn from_api(api: &api::OrcError) -> Self {
|
||||
Self {
|
||||
description: Tok::from_api(api.description),
|
||||
message: api.message.clone(),
|
||||
positions: api.locations.iter().map(ErrPos::from_api).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Eq for OrcErr {}
|
||||
impl PartialEq for OrcErr {
|
||||
fn eq(&self, other: &Self) -> bool { self.description == other.description }
|
||||
fn eq(&self, other: &Self) -> bool { self.description == other.description }
|
||||
}
|
||||
impl From<OrcErr> for Vec<OrcErr> {
|
||||
fn from(value: OrcErr) -> Self { vec![value] }
|
||||
fn from(value: OrcErr) -> Self { vec![value] }
|
||||
}
|
||||
impl fmt::Display for OrcErr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let pstr = self.positions.iter().map(|p| format!("{p:?}")).join("; ");
|
||||
write!(f, "{}: {} @ {}", self.description, self.message, pstr)
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let pstr = self.positions.iter().map(|p| format!("{p:?}")).join("; ");
|
||||
write!(f, "{}: {} @ {}", self.description, self.message, pstr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EmptyErrv;
|
||||
impl fmt::Display for EmptyErrv {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "OrcErrv must not be empty")
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "OrcErrv must not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OrcErrv(Vec<OrcErr>);
|
||||
impl OrcErrv {
|
||||
pub fn new(errors: impl IntoIterator<Item = OrcErr>) -> Result<Self, EmptyErrv> {
|
||||
let v = errors.into_iter().collect_vec();
|
||||
if v.is_empty() { Err(EmptyErrv) } else { Ok(Self(v)) }
|
||||
}
|
||||
#[must_use]
|
||||
pub fn extended<T>(mut self, errors: impl IntoIterator<Item = T>) -> Self
|
||||
where Self: Extend<T> {
|
||||
self.extend(errors);
|
||||
self
|
||||
}
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize { self.0.len() }
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
#[must_use]
|
||||
pub fn any(&self, f: impl FnMut(&OrcErr) -> bool) -> bool { self.0.iter().any(f) }
|
||||
#[must_use]
|
||||
pub fn keep_only(self, f: impl FnMut(&OrcErr) -> bool) -> Option<Self> {
|
||||
let v = self.0.into_iter().filter(f).collect_vec();
|
||||
if v.is_empty() { None } else { Some(Self(v)) }
|
||||
}
|
||||
#[must_use]
|
||||
pub fn one(&self) -> Option<&OrcErr> { (self.0.len() == 1).then(|| &self.0[9]) }
|
||||
pub fn pos_iter(&self) -> impl Iterator<Item = ErrPos> + '_ {
|
||||
self.0.iter().flat_map(|e| e.positions.iter().cloned())
|
||||
}
|
||||
pub fn to_api(&self) -> Vec<api::OrcError> { self.0.iter().map(OrcErr::to_api).collect() }
|
||||
pub fn from_api<'a>(api: impl IntoIterator<Item = &'a api::OrcError>) -> Self {
|
||||
Self(api.into_iter().map(OrcErr::from_api).collect())
|
||||
}
|
||||
pub fn new(errors: impl IntoIterator<Item = OrcErr>) -> Result<Self, EmptyErrv> {
|
||||
let v = errors.into_iter().collect_vec();
|
||||
if v.is_empty() { Err(EmptyErrv) } else { Ok(Self(v)) }
|
||||
}
|
||||
#[must_use]
|
||||
pub fn extended<T>(mut self, errors: impl IntoIterator<Item = T>) -> Self
|
||||
where Self: Extend<T> {
|
||||
self.extend(errors);
|
||||
self
|
||||
}
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize { self.0.len() }
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
#[must_use]
|
||||
pub fn any(&self, f: impl FnMut(&OrcErr) -> bool) -> bool { self.0.iter().any(f) }
|
||||
#[must_use]
|
||||
pub fn keep_only(self, f: impl FnMut(&OrcErr) -> bool) -> Option<Self> {
|
||||
let v = self.0.into_iter().filter(f).collect_vec();
|
||||
if v.is_empty() { None } else { Some(Self(v)) }
|
||||
}
|
||||
#[must_use]
|
||||
pub fn one(&self) -> Option<&OrcErr> { (self.0.len() == 1).then(|| &self.0[9]) }
|
||||
pub fn pos_iter(&self) -> impl Iterator<Item = ErrPos> + '_ {
|
||||
self.0.iter().flat_map(|e| e.positions.iter().cloned())
|
||||
}
|
||||
pub fn to_api(&self) -> Vec<api::OrcError> { self.0.iter().map(OrcErr::to_api).collect() }
|
||||
pub fn from_api<'a>(api: impl IntoIterator<Item = &'a api::OrcError>) -> Self {
|
||||
Self(api.into_iter().map(OrcErr::from_api).collect())
|
||||
}
|
||||
}
|
||||
impl From<OrcErr> for OrcErrv {
|
||||
fn from(value: OrcErr) -> Self { Self(vec![value]) }
|
||||
fn from(value: OrcErr) -> Self { Self(vec![value]) }
|
||||
}
|
||||
impl Add for OrcErrv {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output { Self(self.0.into_iter().chain(rhs.0).collect_vec()) }
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output { Self(self.0.into_iter().chain(rhs.0).collect_vec()) }
|
||||
}
|
||||
impl Extend<OrcErr> for OrcErrv {
|
||||
fn extend<T: IntoIterator<Item = OrcErr>>(&mut self, iter: T) { self.0.extend(iter) }
|
||||
fn extend<T: IntoIterator<Item = OrcErr>>(&mut self, iter: T) { self.0.extend(iter) }
|
||||
}
|
||||
impl Extend<OrcErrv> for OrcErrv {
|
||||
fn extend<T: IntoIterator<Item = OrcErrv>>(&mut self, iter: T) {
|
||||
self.0.extend(iter.into_iter().flatten())
|
||||
}
|
||||
fn extend<T: IntoIterator<Item = OrcErrv>>(&mut self, iter: T) {
|
||||
self.0.extend(iter.into_iter().flatten())
|
||||
}
|
||||
}
|
||||
impl IntoIterator for OrcErrv {
|
||||
type IntoIter = std::vec::IntoIter<OrcErr>;
|
||||
type Item = OrcErr;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||
type IntoIter = std::vec::IntoIter<OrcErr>;
|
||||
type Item = OrcErr;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||
}
|
||||
impl fmt::Display for OrcErrv {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0.iter().join("\n"))
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0.iter().join("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
pub type OrcRes<T> = Result<T, OrcErrv>;
|
||||
|
||||
pub fn mk_err(
|
||||
description: Tok<String>,
|
||||
message: impl AsRef<str>,
|
||||
posv: impl IntoIterator<Item = ErrPos>,
|
||||
description: Tok<String>,
|
||||
message: impl AsRef<str>,
|
||||
posv: impl IntoIterator<Item = ErrPos>,
|
||||
) -> OrcErr {
|
||||
OrcErr {
|
||||
description,
|
||||
message: Arc::new(message.as_ref().to_string()),
|
||||
positions: posv.into_iter().collect(),
|
||||
}
|
||||
OrcErr {
|
||||
description,
|
||||
message: Arc::new(message.as_ref().to_string()),
|
||||
positions: posv.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_errv(
|
||||
description: Tok<String>,
|
||||
message: impl AsRef<str>,
|
||||
posv: impl IntoIterator<Item = ErrPos>,
|
||||
description: Tok<String>,
|
||||
message: impl AsRef<str>,
|
||||
posv: impl IntoIterator<Item = ErrPos>,
|
||||
) -> OrcErrv {
|
||||
mk_err(description, message, posv).into()
|
||||
mk_err(description, message, posv).into()
|
||||
}
|
||||
|
||||
pub trait Reporter {
|
||||
fn report(&self, e: impl Into<OrcErrv>);
|
||||
fn report(&self, e: impl Into<OrcErrv>);
|
||||
}
|
||||
+47
-47
@@ -1,67 +1,67 @@
|
||||
//! Multiple-listener-single-delivery event system.
|
||||
|
||||
use std::mem;
|
||||
use std::sync::mpsc::{self, sync_channel};
|
||||
use std::sync::Mutex;
|
||||
use std::sync::mpsc::{self, sync_channel};
|
||||
|
||||
struct Reply<T, U> {
|
||||
resub: bool,
|
||||
outcome: Result<U, T>,
|
||||
resub: bool,
|
||||
outcome: Result<U, T>,
|
||||
}
|
||||
|
||||
struct Listener<T, E> {
|
||||
sink: mpsc::SyncSender<T>,
|
||||
source: mpsc::Receiver<Reply<T, E>>,
|
||||
sink: mpsc::SyncSender<T>,
|
||||
source: mpsc::Receiver<Reply<T, E>>,
|
||||
}
|
||||
|
||||
pub struct Event<T, U> {
|
||||
listeners: Mutex<Vec<Listener<T, U>>>,
|
||||
listeners: Mutex<Vec<Listener<T, U>>>,
|
||||
}
|
||||
impl<T, U> Event<T, U> {
|
||||
pub const fn new() -> Self { Self { listeners: Mutex::new(Vec::new()) } }
|
||||
pub const fn new() -> Self { Self { listeners: Mutex::new(Vec::new()) } }
|
||||
|
||||
pub fn dispatch(&self, mut ev: T) -> Option<U> {
|
||||
let mut listeners = self.listeners.lock().unwrap();
|
||||
let mut alt_list = Vec::with_capacity(listeners.len());
|
||||
mem::swap(&mut *listeners, &mut alt_list);
|
||||
let mut items = alt_list.into_iter();
|
||||
while let Some(l) = items.next() {
|
||||
l.sink.send(ev).unwrap();
|
||||
let Reply { resub, outcome } = l.source.recv().unwrap();
|
||||
if resub {
|
||||
listeners.push(l);
|
||||
}
|
||||
match outcome {
|
||||
Ok(res) => {
|
||||
listeners.extend(items);
|
||||
return Some(res);
|
||||
},
|
||||
Err(next) => {
|
||||
ev = next;
|
||||
},
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn dispatch(&self, mut ev: T) -> Option<U> {
|
||||
let mut listeners = self.listeners.lock().unwrap();
|
||||
let mut alt_list = Vec::with_capacity(listeners.len());
|
||||
mem::swap(&mut *listeners, &mut alt_list);
|
||||
let mut items = alt_list.into_iter();
|
||||
while let Some(l) = items.next() {
|
||||
l.sink.send(ev).unwrap();
|
||||
let Reply { resub, outcome } = l.source.recv().unwrap();
|
||||
if resub {
|
||||
listeners.push(l);
|
||||
}
|
||||
match outcome {
|
||||
Ok(res) => {
|
||||
listeners.extend(items);
|
||||
return Some(res);
|
||||
},
|
||||
Err(next) => {
|
||||
ev = next;
|
||||
},
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_one<V>(&self, mut filter: impl FnMut(&T) -> bool, f: impl FnOnce(T) -> (U, V)) -> V {
|
||||
let mut listeners = self.listeners.lock().unwrap();
|
||||
let (sink, request) = sync_channel(0);
|
||||
let (response, source) = sync_channel(0);
|
||||
listeners.push(Listener { sink, source });
|
||||
mem::drop(listeners);
|
||||
loop {
|
||||
let t = request.recv().unwrap();
|
||||
if filter(&t) {
|
||||
let (u, v) = f(t);
|
||||
response.send(Reply { resub: false, outcome: Ok(u) }).unwrap();
|
||||
return v;
|
||||
}
|
||||
response.send(Reply { resub: true, outcome: Err(t) }).unwrap();
|
||||
}
|
||||
}
|
||||
pub fn get_one<V>(&self, mut filter: impl FnMut(&T) -> bool, f: impl FnOnce(T) -> (U, V)) -> V {
|
||||
let mut listeners = self.listeners.lock().unwrap();
|
||||
let (sink, request) = sync_channel(0);
|
||||
let (response, source) = sync_channel(0);
|
||||
listeners.push(Listener { sink, source });
|
||||
mem::drop(listeners);
|
||||
loop {
|
||||
let t = request.recv().unwrap();
|
||||
if filter(&t) {
|
||||
let (u, v) = f(t);
|
||||
response.send(Reply { resub: false, outcome: Ok(u) }).unwrap();
|
||||
return v;
|
||||
}
|
||||
response.send(Reply { resub: true, outcome: Err(t) }).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Default for Event<T, U> {
|
||||
fn default() -> Self { Self::new() }
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
+28
-28
@@ -6,45 +6,45 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
|
||||
use hashbrown::HashMap;
|
||||
|
||||
pub struct IdStore<T> {
|
||||
table: OnceLock<Mutex<HashMap<NonZeroU64, T>>>,
|
||||
id: AtomicU64,
|
||||
table: OnceLock<Mutex<HashMap<NonZeroU64, T>>>,
|
||||
id: AtomicU64,
|
||||
}
|
||||
impl<T> IdStore<T> {
|
||||
pub const fn new() -> Self { Self { table: OnceLock::new(), id: AtomicU64::new(1) } }
|
||||
pub fn add(&self, t: T) -> IdRecord<'_, T> {
|
||||
let tbl = self.table.get_or_init(Mutex::default);
|
||||
let mut tbl_g = tbl.lock().unwrap();
|
||||
let id: NonZeroU64 = self.id.fetch_add(1, Ordering::Relaxed).try_into().unwrap();
|
||||
assert!(tbl_g.insert(id, t).is_none(), "atom ID wraparound");
|
||||
IdRecord(id, tbl_g)
|
||||
}
|
||||
pub fn get(&self, id: impl Into<NonZeroU64>) -> Option<IdRecord<'_, T>> {
|
||||
let tbl = self.table.get_or_init(Mutex::default);
|
||||
let tbl_g = tbl.lock().unwrap();
|
||||
let id64 = id.into();
|
||||
if tbl_g.contains_key(&id64) { Some(IdRecord(id64, tbl_g)) } else { None }
|
||||
}
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
pub fn len(&self) -> usize { self.table.get().map(|t| t.lock().unwrap().len()).unwrap_or(0) }
|
||||
pub const fn new() -> Self { Self { table: OnceLock::new(), id: AtomicU64::new(1) } }
|
||||
pub fn add(&self, t: T) -> IdRecord<'_, T> {
|
||||
let tbl = self.table.get_or_init(Mutex::default);
|
||||
let mut tbl_g = tbl.lock().unwrap();
|
||||
let id: NonZeroU64 = self.id.fetch_add(1, Ordering::Relaxed).try_into().unwrap();
|
||||
assert!(tbl_g.insert(id, t).is_none(), "atom ID wraparound");
|
||||
IdRecord(id, tbl_g)
|
||||
}
|
||||
pub fn get(&self, id: impl Into<NonZeroU64>) -> Option<IdRecord<'_, T>> {
|
||||
let tbl = self.table.get_or_init(Mutex::default);
|
||||
let tbl_g = tbl.lock().unwrap();
|
||||
let id64 = id.into();
|
||||
if tbl_g.contains_key(&id64) { Some(IdRecord(id64, tbl_g)) } else { None }
|
||||
}
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
pub fn len(&self) -> usize { self.table.get().map(|t| t.lock().unwrap().len()).unwrap_or(0) }
|
||||
}
|
||||
|
||||
impl<T> Default for IdStore<T> {
|
||||
fn default() -> Self { Self::new() }
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
pub struct IdRecord<'a, T>(NonZeroU64, MutexGuard<'a, HashMap<NonZeroU64, T>>);
|
||||
impl<T> IdRecord<'_, T> {
|
||||
pub fn id(&self) -> NonZeroU64 { self.0 }
|
||||
pub fn remove(mut self) -> T { self.1.remove(&self.0).unwrap() }
|
||||
pub fn id(&self) -> NonZeroU64 { self.0 }
|
||||
pub fn remove(mut self) -> T { self.1.remove(&self.0).unwrap() }
|
||||
}
|
||||
impl<T> Deref for IdRecord<'_, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.1.get(&self.0).expect("Existence checked on construction")
|
||||
}
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.1.get(&self.0).expect("Existence checked on construction")
|
||||
}
|
||||
}
|
||||
impl<T> DerefMut for IdRecord<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.1.get_mut(&self.0).expect("Existence checked on construction")
|
||||
}
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.1.get_mut(&self.0).expect("Existence checked on construction")
|
||||
}
|
||||
}
|
||||
+211
-210
@@ -2,7 +2,7 @@ use std::borrow::Borrow;
|
||||
use std::hash::BuildHasher as _;
|
||||
use std::num::NonZeroU64;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::{atomic, Arc, Mutex, MutexGuard};
|
||||
use std::sync::{Arc, Mutex, MutexGuard, atomic};
|
||||
use std::{fmt, hash, mem};
|
||||
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
@@ -19,148 +19,149 @@ struct ForceSized<T>(T);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Tok<T: Interned> {
|
||||
data: Arc<T>,
|
||||
marker: ForceSized<T::Marker>,
|
||||
data: Arc<T>,
|
||||
marker: ForceSized<T::Marker>,
|
||||
}
|
||||
impl<T: Interned> Tok<T> {
|
||||
pub fn new(data: Arc<T>, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } }
|
||||
pub fn to_api(&self) -> T::Marker { self.marker.0 }
|
||||
pub fn from_api<M>(marker: M) -> Self where M: InternMarker<Interned = T> {
|
||||
deintern(marker)
|
||||
}
|
||||
pub fn arc(&self) -> Arc<T> { self.data.clone() }
|
||||
pub fn new(data: Arc<T>, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } }
|
||||
pub fn to_api(&self) -> T::Marker { self.marker.0 }
|
||||
pub fn from_api<M>(marker: M) -> Self
|
||||
where M: InternMarker<Interned = T> {
|
||||
deintern(marker)
|
||||
}
|
||||
pub fn arc(&self) -> Arc<T> { self.data.clone() }
|
||||
}
|
||||
impl<T: Interned> Deref for Tok<T> {
|
||||
type Target = T;
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target { self.data.as_ref() }
|
||||
fn deref(&self) -> &Self::Target { self.data.as_ref() }
|
||||
}
|
||||
impl<T: Interned> Ord for Tok<T> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.to_api().cmp(&other.to_api()) }
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.to_api().cmp(&other.to_api()) }
|
||||
}
|
||||
impl<T: Interned> PartialOrd for Tok<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
impl<T: Interned> Eq for Tok<T> {}
|
||||
impl<T: Interned> PartialEq for Tok<T> {
|
||||
fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() }
|
||||
fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() }
|
||||
}
|
||||
impl<T: Interned> hash::Hash for Tok<T> {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.to_api().hash(state) }
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.to_api().hash(state) }
|
||||
}
|
||||
impl<T: Interned + fmt::Display> fmt::Display for Tok<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", &*self.data)
|
||||
}
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", &*self.data)
|
||||
}
|
||||
}
|
||||
impl<T: Interned + fmt::Debug> fmt::Debug for Tok<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Token({} -> {:?})", self.to_api().get_id(), self.data.as_ref())
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Token({} -> {:?})", self.to_api().get_id(), self.data.as_ref())
|
||||
}
|
||||
}
|
||||
impl<T: Interned + Encode> Encode for Tok<T> {
|
||||
fn encode<W: std::io::Write + ?Sized>(&self, write: &mut W) { self.data.encode(write) }
|
||||
fn encode<W: std::io::Write + ?Sized>(&self, write: &mut W) { self.data.encode(write) }
|
||||
}
|
||||
impl<T: Interned + Decode> Decode for Tok<T> {
|
||||
fn decode<R: std::io::Read + ?Sized>(read: &mut R) -> Self { intern(&T::decode(read)) }
|
||||
fn decode<R: std::io::Read + ?Sized>(read: &mut R) -> Self { intern(&T::decode(read)) }
|
||||
}
|
||||
|
||||
pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable<Interned = Self> {
|
||||
type Marker: InternMarker<Interned = Self> + Sized;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker;
|
||||
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
|
||||
type Marker: InternMarker<Interned = Self> + Sized;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker;
|
||||
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
|
||||
}
|
||||
|
||||
pub trait Internable: fmt::Debug {
|
||||
type Interned: Interned;
|
||||
fn get_owned(&self) -> Arc<Self::Interned>;
|
||||
type Interned: Interned;
|
||||
fn get_owned(&self) -> Arc<Self::Interned>;
|
||||
}
|
||||
|
||||
pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash + Sized {
|
||||
type Interned: Interned<Marker = Self>;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned>;
|
||||
fn get_id(self) -> NonZeroU64;
|
||||
fn from_id(id: NonZeroU64) -> Self;
|
||||
type Interned: Interned<Marker = Self>;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned>;
|
||||
fn get_id(self) -> NonZeroU64;
|
||||
fn from_id(id: NonZeroU64) -> Self;
|
||||
}
|
||||
|
||||
impl Interned for String {
|
||||
type Marker = api::TStr;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStr(self))
|
||||
}
|
||||
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.strings }
|
||||
type Marker = api::TStr;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStr(self))
|
||||
}
|
||||
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.strings }
|
||||
}
|
||||
impl InternMarker for api::TStr {
|
||||
type Interned = String;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
Tok::new(req.request(api::ExternStr(self)), self)
|
||||
}
|
||||
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||
type Interned = String;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
Tok::new(req.request(api::ExternStr(self)), self)
|
||||
}
|
||||
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||
}
|
||||
impl Internable for str {
|
||||
type Interned = String;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
|
||||
type Interned = String;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
|
||||
}
|
||||
impl Internable for String {
|
||||
type Interned = String;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
|
||||
type Interned = String;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
|
||||
}
|
||||
|
||||
impl Interned for Vec<Tok<String>> {
|
||||
type Marker = api::TStrv;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStrv(Arc::new(self.iter().map(|t| t.to_api()).collect())))
|
||||
}
|
||||
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.vecs }
|
||||
type Marker = api::TStrv;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStrv(Arc::new(self.iter().map(|t| t.to_api()).collect())))
|
||||
}
|
||||
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.vecs }
|
||||
}
|
||||
impl InternMarker for api::TStrv {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
let data =
|
||||
Arc::new(req.request(api::ExternStrv(self)).iter().map(|m| deintern(*m)).collect_vec());
|
||||
Tok::new(data, self)
|
||||
}
|
||||
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
let data =
|
||||
Arc::new(req.request(api::ExternStrv(self)).iter().map(|m| deintern(*m)).collect_vec());
|
||||
Tok::new(data, self)
|
||||
}
|
||||
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||
}
|
||||
impl Internable for [Tok<String>] {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
}
|
||||
impl Internable for Vec<Tok<String>> {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
}
|
||||
impl Internable for Vec<api::TStr> {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> {
|
||||
Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
||||
}
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> {
|
||||
Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
||||
}
|
||||
}
|
||||
impl Internable for [api::TStr] {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> {
|
||||
Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
||||
}
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> {
|
||||
Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of references held to any token by the interner.
|
||||
@@ -168,138 +169,138 @@ const BASE_RC: usize = 3;
|
||||
|
||||
#[test]
|
||||
fn base_rc_correct() {
|
||||
let tok = Tok::new(Arc::new("foo".to_string()), api::TStr(1.try_into().unwrap()));
|
||||
let mut bimap = Bimap::default();
|
||||
bimap.insert(tok.clone());
|
||||
assert_eq!(Arc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
|
||||
let tok = Tok::new(Arc::new("foo".to_string()), api::TStr(1.try_into().unwrap()));
|
||||
let mut bimap = Bimap::default();
|
||||
bimap.insert(tok.clone());
|
||||
assert_eq!(Arc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
|
||||
}
|
||||
|
||||
pub struct Bimap<T: Interned> {
|
||||
intern: HashMap<Arc<T>, Tok<T>>,
|
||||
by_id: HashMap<T::Marker, Tok<T>>,
|
||||
intern: HashMap<Arc<T>, Tok<T>>,
|
||||
by_id: HashMap<T::Marker, Tok<T>>,
|
||||
}
|
||||
impl<T: Interned> Bimap<T> {
|
||||
pub fn insert(&mut self, token: Tok<T>) {
|
||||
self.intern.insert(token.data.clone(), token.clone());
|
||||
self.by_id.insert(token.to_api(), token);
|
||||
}
|
||||
pub fn insert(&mut self, token: Tok<T>) {
|
||||
self.intern.insert(token.data.clone(), token.clone());
|
||||
self.by_id.insert(token.to_api(), token);
|
||||
}
|
||||
|
||||
pub fn by_marker(&self, marker: T::Marker) -> Option<Tok<T>> { self.by_id.get(&marker).cloned() }
|
||||
pub fn by_marker(&self, marker: T::Marker) -> Option<Tok<T>> { self.by_id.get(&marker).cloned() }
|
||||
|
||||
pub fn by_value<Q: Eq + hash::Hash>(&self, q: &Q) -> Option<Tok<T>>
|
||||
where T: Borrow<Q> {
|
||||
(self.intern.raw_entry())
|
||||
.from_hash(self.intern.hasher().hash_one(q), |k| k.as_ref().borrow() == q)
|
||||
.map(|p| p.1.clone())
|
||||
}
|
||||
pub fn by_value<Q: Eq + hash::Hash>(&self, q: &Q) -> Option<Tok<T>>
|
||||
where T: Borrow<Q> {
|
||||
(self.intern.raw_entry())
|
||||
.from_hash(self.intern.hasher().hash_one(q), |k| k.as_ref().borrow() == q)
|
||||
.map(|p| p.1.clone())
|
||||
}
|
||||
|
||||
pub fn sweep_replica(&mut self) -> Vec<T::Marker> {
|
||||
(self.intern)
|
||||
.extract_if(|k, _| Arc::strong_count(k) == BASE_RC)
|
||||
.map(|(_, v)| {
|
||||
self.by_id.remove(&v.to_api());
|
||||
v.to_api()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
pub fn sweep_replica(&mut self) -> Vec<T::Marker> {
|
||||
(self.intern)
|
||||
.extract_if(|k, _| Arc::strong_count(k) == BASE_RC)
|
||||
.map(|(_, v)| {
|
||||
self.by_id.remove(&v.to_api());
|
||||
v.to_api()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn sweep_master(&mut self, retained: HashSet<T::Marker>) {
|
||||
self.intern.retain(|k, v| BASE_RC < Arc::strong_count(k) || retained.contains(&v.to_api()))
|
||||
}
|
||||
pub fn sweep_master(&mut self, retained: HashSet<T::Marker>) {
|
||||
self.intern.retain(|k, v| BASE_RC < Arc::strong_count(k) || retained.contains(&v.to_api()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Interned> Default for Bimap<T> {
|
||||
fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() } }
|
||||
fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() } }
|
||||
}
|
||||
|
||||
pub trait UpComm {
|
||||
fn up<R: Request>(&self, req: R) -> R::Response;
|
||||
fn up<R: Request>(&self, req: R) -> R::Response;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TypedInterners {
|
||||
strings: Bimap<String>,
|
||||
vecs: Bimap<Vec<Tok<String>>>,
|
||||
strings: Bimap<String>,
|
||||
vecs: Bimap<Vec<Tok<String>>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
interners: TypedInterners,
|
||||
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
||||
interners: TypedInterners,
|
||||
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
||||
}
|
||||
|
||||
static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1);
|
||||
static INTERNER: Mutex<Option<Interner>> = Mutex::new(None);
|
||||
|
||||
pub fn interner() -> impl DerefMut<Target = Interner> {
|
||||
struct G(MutexGuard<'static, Option<Interner>>);
|
||||
impl Deref for G {
|
||||
type Target = Interner;
|
||||
fn deref(&self) -> &Self::Target { self.0.as_ref().expect("Guard pre-initialized") }
|
||||
}
|
||||
impl DerefMut for G {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.0.as_mut().expect("Guard pre-iniitialized")
|
||||
}
|
||||
}
|
||||
let mut g = INTERNER.lock().unwrap();
|
||||
g.get_or_insert_with(Interner::default);
|
||||
G(g)
|
||||
struct G(MutexGuard<'static, Option<Interner>>);
|
||||
impl Deref for G {
|
||||
type Target = Interner;
|
||||
fn deref(&self) -> &Self::Target { self.0.as_ref().expect("Guard pre-initialized") }
|
||||
}
|
||||
impl DerefMut for G {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.0.as_mut().expect("Guard pre-iniitialized")
|
||||
}
|
||||
}
|
||||
let mut g = INTERNER.lock().unwrap();
|
||||
g.get_or_insert_with(Interner::default);
|
||||
G(g)
|
||||
}
|
||||
|
||||
pub fn init_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) {
|
||||
let mut g = INTERNER.lock().unwrap();
|
||||
assert!(g.is_none(), "Attempted to initialize replica interner after first use");
|
||||
*g = Some(Interner {
|
||||
master: Some(Box::new(req)),
|
||||
interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() },
|
||||
})
|
||||
let mut g = INTERNER.lock().unwrap();
|
||||
assert!(g.is_none(), "Attempted to initialize replica interner after first use");
|
||||
*g = Some(Interner {
|
||||
master: Some(Box::new(req)),
|
||||
interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() },
|
||||
})
|
||||
}
|
||||
|
||||
pub fn intern<T: Interned>(t: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
|
||||
let data = t.get_owned();
|
||||
let mut g = interner();
|
||||
let job = format!("{t:?} in {}", if g.master.is_some() { "replica" } else { "master" });
|
||||
eprintln!("Interning {job}");
|
||||
let typed = T::bimap(&mut g.interners);
|
||||
if let Some(tok) = typed.by_value(&data) {
|
||||
return tok;
|
||||
}
|
||||
let marker = match &mut g.master {
|
||||
Some(c) => data.clone().intern(&**c),
|
||||
None =>
|
||||
T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()),
|
||||
};
|
||||
let tok = Tok::new(data, marker);
|
||||
T::bimap(&mut g.interners).insert(tok.clone());
|
||||
mem::drop(g);
|
||||
eprintln!("Interned {job}");
|
||||
tok
|
||||
let data = t.get_owned();
|
||||
let mut g = interner();
|
||||
let job = format!("{t:?} in {}", if g.master.is_some() { "replica" } else { "master" });
|
||||
eprintln!("Interning {job}");
|
||||
let typed = T::bimap(&mut g.interners);
|
||||
if let Some(tok) = typed.by_value(&data) {
|
||||
return tok;
|
||||
}
|
||||
let marker = match &mut g.master {
|
||||
Some(c) => data.clone().intern(&**c),
|
||||
None =>
|
||||
T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()),
|
||||
};
|
||||
let tok = Tok::new(data, marker);
|
||||
T::bimap(&mut g.interners).insert(tok.clone());
|
||||
mem::drop(g);
|
||||
eprintln!("Interned {job}");
|
||||
tok
|
||||
}
|
||||
|
||||
fn deintern<M: InternMarker>(marker: M) -> Tok<M::Interned> {
|
||||
let mut g = interner();
|
||||
if let Some(tok) = M::Interned::bimap(&mut g.interners).by_marker(marker) {
|
||||
return tok;
|
||||
}
|
||||
let master = g.master.as_mut().expect("ID not in local interner and this is master");
|
||||
let token = marker.resolve(&**master);
|
||||
M::Interned::bimap(&mut g.interners).insert(token.clone());
|
||||
token
|
||||
let mut g = interner();
|
||||
if let Some(tok) = M::Interned::bimap(&mut g.interners).by_marker(marker) {
|
||||
return tok;
|
||||
}
|
||||
let master = g.master.as_mut().expect("ID not in local interner and this is master");
|
||||
let token = marker.resolve(&**master);
|
||||
M::Interned::bimap(&mut g.interners).insert(token.clone());
|
||||
token
|
||||
}
|
||||
|
||||
pub fn merge_retained(into: &mut api::Retained, from: &api::Retained) {
|
||||
into.strings = into.strings.iter().chain(&from.strings).copied().unique().collect();
|
||||
into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect();
|
||||
into.strings = into.strings.iter().chain(&from.strings).copied().unique().collect();
|
||||
into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect();
|
||||
}
|
||||
|
||||
pub fn sweep_replica() -> api::Retained {
|
||||
let mut g = interner();
|
||||
assert!(g.master.is_some(), "Not a replica");
|
||||
api::Retained {
|
||||
strings: g.interners.strings.sweep_replica(),
|
||||
vecs: g.interners.vecs.sweep_replica(),
|
||||
}
|
||||
let mut g = interner();
|
||||
assert!(g.master.is_some(), "Not a replica");
|
||||
api::Retained {
|
||||
strings: g.interners.strings.sweep_replica(),
|
||||
vecs: g.interners.vecs.sweep_replica(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a thread-local token instance and copy it. This ensures that the
|
||||
@@ -308,47 +309,47 @@ pub fn sweep_replica() -> api::Retained {
|
||||
/// expression (i.e. a literal).
|
||||
#[macro_export]
|
||||
macro_rules! intern {
|
||||
($ty:ty : $expr:expr) => {{
|
||||
thread_local! {
|
||||
static VALUE: $crate::interner::Tok<<$ty as $crate::interner::Internable>::Interned>
|
||||
= $crate::interner::intern::<
|
||||
<$ty as $crate::interner::Internable>::Interned
|
||||
>($expr as &$ty);
|
||||
}
|
||||
VALUE.with(|v| v.clone())
|
||||
}};
|
||||
($ty:ty : $expr:expr) => {{
|
||||
thread_local! {
|
||||
static VALUE: $crate::interner::Tok<<$ty as $crate::interner::Internable>::Interned>
|
||||
= $crate::interner::intern::<
|
||||
<$ty as $crate::interner::Internable>::Interned
|
||||
>($expr as &$ty);
|
||||
}
|
||||
VALUE.with(|v| v.clone())
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn sweep_master(retained: api::Retained) {
|
||||
let mut g = interner();
|
||||
assert!(g.master.is_none(), "Not master");
|
||||
g.interners.strings.sweep_master(retained.strings.into_iter().collect());
|
||||
g.interners.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||
let mut g = interner();
|
||||
assert!(g.master.is_none(), "Not master");
|
||||
g.interners.strings.sweep_master(retained.strings.into_iter().collect());
|
||||
g.interners.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::num::NonZero;
|
||||
use std::num::NonZero;
|
||||
|
||||
use orchid_api_traits::{enc_vec, Decode};
|
||||
use orchid_api_traits::{Decode, enc_vec};
|
||||
|
||||
use super::*;
|
||||
use crate::api;
|
||||
use super::*;
|
||||
use crate::api;
|
||||
|
||||
#[test]
|
||||
fn test_i() {
|
||||
let _: Tok<String> = intern!(str: "foo");
|
||||
let _: Tok<Vec<Tok<String>>> = intern!([Tok<String>]: &[
|
||||
intern!(str: "bar"),
|
||||
intern!(str: "baz")
|
||||
]);
|
||||
}
|
||||
#[test]
|
||||
fn test_i() {
|
||||
let _: Tok<String> = intern!(str: "foo");
|
||||
let _: Tok<Vec<Tok<String>>> = intern!([Tok<String>]: &[
|
||||
intern!(str: "bar"),
|
||||
intern!(str: "baz")
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_coding() {
|
||||
let coded = api::TStr(NonZero::new(3u64).unwrap());
|
||||
let mut enc = &enc_vec(&coded)[..];
|
||||
api::TStr::decode(&mut enc);
|
||||
assert_eq!(enc, [], "Did not consume all of {enc:?}")
|
||||
}
|
||||
#[test]
|
||||
fn test_coding() {
|
||||
let coded = api::TStr(NonZero::new(3u64).unwrap());
|
||||
let mut enc = &enc_vec(&coded)[..];
|
||||
api::TStr::decode(&mut enc);
|
||||
assert_eq!(enc, [], "Did not consume all of {enc:?}")
|
||||
}
|
||||
}
|
||||
+28
-28
@@ -8,38 +8,38 @@ use never::Never;
|
||||
/// Combine two hashmaps via an infallible value merger. See also
|
||||
/// [try_join_maps]
|
||||
pub fn join_maps<K: Eq + Hash, V>(
|
||||
left: HashMap<K, V>,
|
||||
right: HashMap<K, V>,
|
||||
mut merge: impl FnMut(&K, V, V) -> V,
|
||||
left: HashMap<K, V>,
|
||||
right: HashMap<K, V>,
|
||||
mut merge: impl FnMut(&K, V, V) -> V,
|
||||
) -> HashMap<K, V> {
|
||||
let (val, ev) = try_join_maps::<K, V, Never>(left, right, |k, l, r| Ok(merge(k, l, r)));
|
||||
if let Some(e) = ev.first() {
|
||||
match *e {}
|
||||
}
|
||||
val
|
||||
let (val, ev) = try_join_maps::<K, V, Never>(left, right, |k, l, r| Ok(merge(k, l, r)));
|
||||
if let Some(e) = ev.first() {
|
||||
match *e {}
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
/// Combine two hashmaps via a fallible value merger. See also [join_maps]
|
||||
pub fn try_join_maps<K: Eq + Hash, V, E>(
|
||||
left: HashMap<K, V>,
|
||||
mut right: HashMap<K, V>,
|
||||
mut merge: impl FnMut(&K, V, V) -> Result<V, E>,
|
||||
left: HashMap<K, V>,
|
||||
mut right: HashMap<K, V>,
|
||||
mut merge: impl FnMut(&K, V, V) -> Result<V, E>,
|
||||
) -> (HashMap<K, V>, Vec<E>) {
|
||||
let mut mixed = HashMap::with_capacity(left.len() + right.len());
|
||||
let mut errors = Vec::new();
|
||||
for (key, lval) in left {
|
||||
let val = match right.remove(&key) {
|
||||
None => lval,
|
||||
Some(rval) => match merge(&key, lval, rval) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
errors.push(e);
|
||||
continue;
|
||||
},
|
||||
},
|
||||
};
|
||||
mixed.insert(key, val);
|
||||
}
|
||||
mixed.extend(right);
|
||||
(mixed, errors)
|
||||
let mut mixed = HashMap::with_capacity(left.len() + right.len());
|
||||
let mut errors = Vec::new();
|
||||
for (key, lval) in left {
|
||||
let val = match right.remove(&key) {
|
||||
None => lval,
|
||||
Some(rval) => match merge(&key, lval, rval) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
errors.push(e);
|
||||
continue;
|
||||
},
|
||||
},
|
||||
};
|
||||
mixed.insert(key, val);
|
||||
}
|
||||
mixed.extend(right);
|
||||
(mixed, errors)
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
use orchid_api as api;
|
||||
|
||||
pub mod box_cow;
|
||||
pub mod boxed_iter;
|
||||
pub mod char_filter;
|
||||
pub mod clone;
|
||||
pub mod combine;
|
||||
pub mod event;
|
||||
pub mod msg;
|
||||
pub mod box_cow;
|
||||
pub mod char_filter;
|
||||
pub mod error;
|
||||
pub mod event;
|
||||
pub mod id_store;
|
||||
pub mod interner;
|
||||
pub mod join;
|
||||
pub mod location;
|
||||
pub mod logging;
|
||||
pub mod macros;
|
||||
mod match_mapping;
|
||||
pub mod msg;
|
||||
pub mod name;
|
||||
pub mod number;
|
||||
pub mod parse;
|
||||
@@ -22,5 +24,3 @@ pub mod sequence;
|
||||
pub mod side;
|
||||
pub mod tokens;
|
||||
pub mod tree;
|
||||
pub mod macros;
|
||||
mod match_mapping;
|
||||
+101
-107
@@ -1,148 +1,142 @@
|
||||
//! Structures that show where code or semantic elements came from
|
||||
|
||||
use crate::match_mapping;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Range;
|
||||
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::interner::{intern, Tok};
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::name::Sym;
|
||||
use crate::{api, intern, sym};
|
||||
use crate::{api, intern, match_mapping, sym};
|
||||
|
||||
trait_set! {
|
||||
pub trait GetSrc = FnMut(&Sym) -> Tok<String>;
|
||||
pub trait GetSrc = FnMut(&Sym) -> Tok<String>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Pos {
|
||||
None,
|
||||
SlotTarget,
|
||||
/// Used in functions to denote the generated code that carries on the
|
||||
/// location of the call. Not allowed in the const tree.
|
||||
Inherit,
|
||||
Gen(CodeGenInfo),
|
||||
/// Range and file
|
||||
SourceRange(SourceRange),
|
||||
/// Range only, file implied. Most notably used by parsers
|
||||
Range(Range<u32>),
|
||||
None,
|
||||
SlotTarget,
|
||||
/// Used in functions to denote the generated code that carries on the
|
||||
/// location of the call. Not allowed in the const tree.
|
||||
Inherit,
|
||||
Gen(CodeGenInfo),
|
||||
/// Range and file
|
||||
SourceRange(SourceRange),
|
||||
/// Range only, file implied. Most notably used by parsers
|
||||
Range(Range<u32>),
|
||||
}
|
||||
impl Pos {
|
||||
pub fn pretty_print(&self, get_src: &mut impl GetSrc) -> String {
|
||||
match self {
|
||||
Self::Gen(g) => g.to_string(),
|
||||
Self::SourceRange(sr) => sr.pretty_print(&get_src(&sr.path)),
|
||||
// Can't pretty print partial and meta-location
|
||||
other => format!("{other:?}"),
|
||||
}
|
||||
}
|
||||
pub fn from_api(api: &api::Location) -> Self {
|
||||
match_mapping!(api, api::Location => Pos {
|
||||
None, Inherit, SlotTarget,
|
||||
Range(r.clone()),
|
||||
Gen(cgi => CodeGenInfo::from_api(cgi)),
|
||||
SourceRange(sr => SourceRange::from_api(sr))
|
||||
})
|
||||
}
|
||||
pub fn to_api(&self) -> api::Location {
|
||||
match_mapping!(self, Pos => api::Location {
|
||||
None, Inherit, SlotTarget,
|
||||
Range(r.clone()),
|
||||
Gen(cgi.to_api()),
|
||||
SourceRange(sr.to_api()),
|
||||
})
|
||||
}
|
||||
pub fn pretty_print(&self, get_src: &mut impl GetSrc) -> String {
|
||||
match self {
|
||||
Self::Gen(g) => g.to_string(),
|
||||
Self::SourceRange(sr) => sr.pretty_print(&get_src(&sr.path)),
|
||||
// Can't pretty print partial and meta-location
|
||||
other => format!("{other:?}"),
|
||||
}
|
||||
}
|
||||
pub fn from_api(api: &api::Location) -> Self {
|
||||
match_mapping!(api, api::Location => Pos {
|
||||
None, Inherit, SlotTarget,
|
||||
Range(r.clone()),
|
||||
Gen(cgi => CodeGenInfo::from_api(cgi)),
|
||||
SourceRange(sr => SourceRange::from_api(sr))
|
||||
})
|
||||
}
|
||||
pub fn to_api(&self) -> api::Location {
|
||||
match_mapping!(self, Pos => api::Location {
|
||||
None, Inherit, SlotTarget,
|
||||
Range(r.clone()),
|
||||
Gen(cgi.to_api()),
|
||||
SourceRange(sr.to_api()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Exact source code location. Includes where the code was loaded from, what
|
||||
/// the original source code was, and a byte range.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SourceRange {
|
||||
pub(crate) path: Sym,
|
||||
pub(crate) range: Range<u32>,
|
||||
pub(crate) path: Sym,
|
||||
pub(crate) range: Range<u32>,
|
||||
}
|
||||
impl SourceRange {
|
||||
pub fn new(range: &Range<u32>, path: &Sym) -> Self {
|
||||
Self { range: range.clone(), path: path.clone() }
|
||||
}
|
||||
/// Create a dud [SourceRange] for testing. Its value is unspecified and
|
||||
/// volatile.
|
||||
pub fn mock() -> Self { Self { range: 0..1, path: sym!(test) } }
|
||||
/// Path the source text was loaded from
|
||||
pub fn path(&self) -> Sym { self.path.clone() }
|
||||
/// Byte range
|
||||
pub fn range(&self) -> Range<u32> { self.range.clone() }
|
||||
/// 0-based index of first byte
|
||||
pub fn start(&self) -> u32 { self.range.start }
|
||||
/// 0-based index of last byte + 1
|
||||
pub fn end(&self) -> u32 { self.range.end }
|
||||
/// Syntactic location
|
||||
pub fn pos(&self) -> Pos { Pos::SourceRange(self.clone()) }
|
||||
/// Transform the numeric byte range
|
||||
pub fn map_range(&self, map: impl FnOnce(Range<u32>) -> Range<u32>) -> Self {
|
||||
Self { range: map(self.range()), path: self.path() }
|
||||
}
|
||||
pub fn pretty_print(&self, src: &str) -> String {
|
||||
let (sl, sc) = pos2lc(src, self.range.start);
|
||||
let (el, ec) = pos2lc(src, self.range.end);
|
||||
match (el == sl, ec <= sc + 1) {
|
||||
(true, true) => format!("{sl}:{sc}"),
|
||||
(true, false) => format!("{sl}:{sc}..{ec}"),
|
||||
(false, _) => format!("{sl}:{sc}..{el}:{ec}"),
|
||||
}
|
||||
}
|
||||
pub fn zw(path: Sym, pos: u32) -> Self {
|
||||
Self { path, range: pos..pos }
|
||||
}
|
||||
fn from_api(api: &api::SourceRange) -> Self {
|
||||
Self { path: Sym::from_api(api.path), range: api.range.clone() }
|
||||
}
|
||||
fn to_api(&self) -> api::SourceRange {
|
||||
api::SourceRange { path: self.path.to_api(), range: self.range.clone() }
|
||||
}
|
||||
pub fn new(range: &Range<u32>, path: &Sym) -> Self {
|
||||
Self { range: range.clone(), path: path.clone() }
|
||||
}
|
||||
/// Create a dud [SourceRange] for testing. Its value is unspecified and
|
||||
/// volatile.
|
||||
pub fn mock() -> Self { Self { range: 0..1, path: sym!(test) } }
|
||||
/// Path the source text was loaded from
|
||||
pub fn path(&self) -> Sym { self.path.clone() }
|
||||
/// Byte range
|
||||
pub fn range(&self) -> Range<u32> { self.range.clone() }
|
||||
/// 0-based index of first byte
|
||||
pub fn start(&self) -> u32 { self.range.start }
|
||||
/// 0-based index of last byte + 1
|
||||
pub fn end(&self) -> u32 { self.range.end }
|
||||
/// Syntactic location
|
||||
pub fn pos(&self) -> Pos { Pos::SourceRange(self.clone()) }
|
||||
/// Transform the numeric byte range
|
||||
pub fn map_range(&self, map: impl FnOnce(Range<u32>) -> Range<u32>) -> Self {
|
||||
Self { range: map(self.range()), path: self.path() }
|
||||
}
|
||||
pub fn pretty_print(&self, src: &str) -> String {
|
||||
let (sl, sc) = pos2lc(src, self.range.start);
|
||||
let (el, ec) = pos2lc(src, self.range.end);
|
||||
match (el == sl, ec <= sc + 1) {
|
||||
(true, true) => format!("{sl}:{sc}"),
|
||||
(true, false) => format!("{sl}:{sc}..{ec}"),
|
||||
(false, _) => format!("{sl}:{sc}..{el}:{ec}"),
|
||||
}
|
||||
}
|
||||
pub fn zw(path: Sym, pos: u32) -> Self { Self { path, range: pos..pos } }
|
||||
fn from_api(api: &api::SourceRange) -> Self {
|
||||
Self { path: Sym::from_api(api.path), range: api.range.clone() }
|
||||
}
|
||||
fn to_api(&self) -> api::SourceRange {
|
||||
api::SourceRange { path: self.path.to_api(), range: self.range.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about a code generator attached to the generated code
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct CodeGenInfo {
|
||||
/// formatted like a Rust namespace
|
||||
pub generator: Sym,
|
||||
/// Unformatted user message with relevant circumstances and parameters
|
||||
pub details: Tok<String>,
|
||||
/// formatted like a Rust namespace
|
||||
pub generator: Sym,
|
||||
/// Unformatted user message with relevant circumstances and parameters
|
||||
pub details: Tok<String>,
|
||||
}
|
||||
impl CodeGenInfo {
|
||||
/// A codegen marker with no user message and parameters
|
||||
pub fn no_details(generator: Sym) -> Self { Self { generator, details: intern!(str: "") } }
|
||||
/// A codegen marker with a user message or parameters
|
||||
pub fn details(generator: Sym, details: impl AsRef<str>) -> Self {
|
||||
Self { generator, details: intern(details.as_ref()) }
|
||||
}
|
||||
/// Syntactic location
|
||||
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
|
||||
fn from_api(api: &api::CodeGenInfo) -> Self {
|
||||
Self {
|
||||
generator: Sym::from_api(api.generator),
|
||||
details: Tok::from_api(api.details),
|
||||
}
|
||||
}
|
||||
fn to_api(&self) -> api::CodeGenInfo {
|
||||
api::CodeGenInfo { generator: self.generator.to_api(), details: self.details.to_api() }
|
||||
}
|
||||
/// A codegen marker with no user message and parameters
|
||||
pub fn no_details(generator: Sym) -> Self { Self { generator, details: intern!(str: "") } }
|
||||
/// A codegen marker with a user message or parameters
|
||||
pub fn details(generator: Sym, details: impl AsRef<str>) -> Self {
|
||||
Self { generator, details: intern(details.as_ref()) }
|
||||
}
|
||||
/// Syntactic location
|
||||
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
|
||||
fn from_api(api: &api::CodeGenInfo) -> Self {
|
||||
Self { generator: Sym::from_api(api.generator), details: Tok::from_api(api.details) }
|
||||
}
|
||||
fn to_api(&self) -> api::CodeGenInfo {
|
||||
api::CodeGenInfo { generator: self.generator.to_api(), details: self.details.to_api() }
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for CodeGenInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CodeGenInfo({self})") }
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CodeGenInfo({self})") }
|
||||
}
|
||||
impl fmt::Display for CodeGenInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "generated by {}", self.generator)?;
|
||||
if !self.details.is_empty() { write!(f, ", details: {}", self.details) } else { write!(f, ".") }
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "generated by {}", self.generator)?;
|
||||
if !self.details.is_empty() { write!(f, ", details: {}", self.details) } else { write!(f, ".") }
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn pos2lc(s: &str, i: u32) -> (u32, u32) {
|
||||
s.chars()
|
||||
.take(i.try_into().unwrap())
|
||||
.fold((1, 1), |(line, col), char| if char == '\n' { (line + 1, 1) } else { (line, col + 1) })
|
||||
s.chars()
|
||||
.take(i.try_into().unwrap())
|
||||
.fold((1, 1), |(line, col), char| if char == '\n' { (line + 1, 1) } else { (line, col + 1) })
|
||||
}
|
||||
+18
-18
@@ -1,6 +1,6 @@
|
||||
use std::fmt::Arguments;
|
||||
use std::fs::File;
|
||||
use std::io::{stderr, Write};
|
||||
use std::io::{Write, stderr};
|
||||
|
||||
pub use api::LogStrategy;
|
||||
use itertools::Itertools;
|
||||
@@ -10,21 +10,21 @@ use crate::api;
|
||||
#[derive(Clone)]
|
||||
pub struct Logger(api::LogStrategy);
|
||||
impl Logger {
|
||||
pub fn new(strat: api::LogStrategy) -> Self { Self(strat) }
|
||||
pub fn log(&self, msg: impl AsRef<str>) { writeln!(self, "{}", msg.as_ref()) }
|
||||
pub fn strat(&self) -> api::LogStrategy { self.0.clone() }
|
||||
pub fn log_buf(&self, event: impl AsRef<str>, buf: &[u8]) {
|
||||
if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) {
|
||||
writeln!(self, "{}: [{}]", event.as_ref(), buf.iter().map(|b| format!("{b:02x}")).join(" "))
|
||||
}
|
||||
}
|
||||
pub fn write_fmt(&self, fmt: Arguments) {
|
||||
match &self.0 {
|
||||
api::LogStrategy::StdErr => stderr().write_fmt(fmt).expect("Could not write to stderr!"),
|
||||
api::LogStrategy::File(f) => {
|
||||
let mut file = File::open(f).expect("Could not open logfile");
|
||||
file.write_fmt(fmt).expect("Could not write to logfile");
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn new(strat: api::LogStrategy) -> Self { Self(strat) }
|
||||
pub fn log(&self, msg: impl AsRef<str>) { writeln!(self, "{}", msg.as_ref()) }
|
||||
pub fn strat(&self) -> api::LogStrategy { self.0.clone() }
|
||||
pub fn log_buf(&self, event: impl AsRef<str>, buf: &[u8]) {
|
||||
if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) {
|
||||
writeln!(self, "{}: [{}]", event.as_ref(), buf.iter().map(|b| format!("{b:02x}")).join(" "))
|
||||
}
|
||||
}
|
||||
pub fn write_fmt(&self, fmt: Arguments) {
|
||||
match &self.0 {
|
||||
api::LogStrategy::StdErr => stderr().write_fmt(fmt).expect("Could not write to stderr!"),
|
||||
api::LogStrategy::File(f) => {
|
||||
let mut file = File::open(f).expect("Could not open logfile");
|
||||
file.write_fmt(fmt).expect("Could not write to logfile");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-57
@@ -13,84 +13,84 @@ use crate::{api, match_mapping};
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct MacroSlot<'a>(api::MacroTreeId, PhantomData<&'a ()>);
|
||||
impl MacroSlot<'_> {
|
||||
pub fn id(self) -> api::MacroTreeId { self.0 }
|
||||
pub fn id(self) -> api::MacroTreeId { self.0 }
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
pub trait MacroAtomToApi<A> = FnMut(&A) -> api::MacroToken;
|
||||
pub trait MacroAtomFromApi<'a, A> = FnMut(&api::Atom) -> MTok<'a, A>;
|
||||
pub trait MacroAtomToApi<A> = FnMut(&A) -> api::MacroToken;
|
||||
pub trait MacroAtomFromApi<'a, A> = FnMut(&api::Atom) -> MTok<'a, A>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MTree<'a, A> {
|
||||
pub pos: Pos,
|
||||
pub tok: Arc<MTok<'a, A>>,
|
||||
pub pos: Pos,
|
||||
pub tok: Arc<MTok<'a, A>>,
|
||||
}
|
||||
impl<'a, A> MTree<'a, A> {
|
||||
pub(crate) fn from_api(api: &api::MacroTree, do_atom: &mut impl MacroAtomFromApi<'a, A>) -> Self {
|
||||
Self { pos: Pos::from_api(&api.location), tok: Arc::new(MTok::from_api(&api.token, do_atom)) }
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroTree {
|
||||
api::MacroTree { location: self.pos.to_api(), token: self.tok.to_api(do_atom) }
|
||||
}
|
||||
pub(crate) fn from_api(api: &api::MacroTree, do_atom: &mut impl MacroAtomFromApi<'a, A>) -> Self {
|
||||
Self { pos: Pos::from_api(&api.location), tok: Arc::new(MTok::from_api(&api.token, do_atom)) }
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroTree {
|
||||
api::MacroTree { location: self.pos.to_api(), token: self.tok.to_api(do_atom) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum MTok<'a, A> {
|
||||
S(Paren, Vec<MTree<'a, A>>),
|
||||
Name(Sym),
|
||||
Slot(MacroSlot<'a>),
|
||||
Lambda(Vec<MTree<'a, A>>, Vec<MTree<'a, A>>),
|
||||
Ph(Ph),
|
||||
Atom(A),
|
||||
/// Used in extensions to directly return input
|
||||
Ref(Arc<MTok<'a, Never>>),
|
||||
/// Used in the matcher to skip previous macro output which can only go in
|
||||
/// vectorial placeholders
|
||||
Done(Arc<MTok<'a, A>>),
|
||||
S(Paren, Vec<MTree<'a, A>>),
|
||||
Name(Sym),
|
||||
Slot(MacroSlot<'a>),
|
||||
Lambda(Vec<MTree<'a, A>>, Vec<MTree<'a, A>>),
|
||||
Ph(Ph),
|
||||
Atom(A),
|
||||
/// Used in extensions to directly return input
|
||||
Ref(Arc<MTok<'a, Never>>),
|
||||
/// Used in the matcher to skip previous macro output which can only go in
|
||||
/// vectorial placeholders
|
||||
Done(Arc<MTok<'a, A>>),
|
||||
}
|
||||
impl<'a, A> MTok<'a, A> {
|
||||
pub(crate) fn from_api(
|
||||
api: &api::MacroToken,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
) -> Self {
|
||||
match_mapping!(&api, api::MacroToken => MTok::<'a, A> {
|
||||
Lambda(x => mtreev_from_api(x, do_atom), b => mtreev_from_api(b, do_atom)),
|
||||
Name(t => Sym::from_api(*t)),
|
||||
Slot(tk => MacroSlot(*tk, PhantomData)),
|
||||
S(p.clone(), b => mtreev_from_api(b, do_atom)),
|
||||
Ph(ph => Ph::from_api(ph)),
|
||||
} {
|
||||
api::MacroToken::Atom(a) => do_atom(a)
|
||||
})
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroToken {
|
||||
fn sink(n: &Never) -> api::MacroToken { match *n {} }
|
||||
match_mapping!(&self, MTok => api::MacroToken {
|
||||
Lambda(x => mtreev_to_api(x, do_atom), b => mtreev_to_api(b, do_atom)),
|
||||
Name(t.tok().to_api()),
|
||||
Ph(ph.to_api()),
|
||||
S(p.clone(), b => mtreev_to_api(b, do_atom)),
|
||||
Slot(tk.0.clone()),
|
||||
} {
|
||||
MTok::Ref(r) => r.to_api(&mut sink),
|
||||
MTok::Done(t) => t.to_api(do_atom),
|
||||
MTok::Atom(a) => do_atom(a),
|
||||
})
|
||||
}
|
||||
pub fn at(self, pos: Pos) -> MTree<'a, A> { MTree { pos, tok: Arc::new(self) } }
|
||||
pub(crate) fn from_api(
|
||||
api: &api::MacroToken,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
) -> Self {
|
||||
match_mapping!(&api, api::MacroToken => MTok::<'a, A> {
|
||||
Lambda(x => mtreev_from_api(x, do_atom), b => mtreev_from_api(b, do_atom)),
|
||||
Name(t => Sym::from_api(*t)),
|
||||
Slot(tk => MacroSlot(*tk, PhantomData)),
|
||||
S(p.clone(), b => mtreev_from_api(b, do_atom)),
|
||||
Ph(ph => Ph::from_api(ph)),
|
||||
} {
|
||||
api::MacroToken::Atom(a) => do_atom(a)
|
||||
})
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroToken {
|
||||
fn sink(n: &Never) -> api::MacroToken { match *n {} }
|
||||
match_mapping!(&self, MTok => api::MacroToken {
|
||||
Lambda(x => mtreev_to_api(x, do_atom), b => mtreev_to_api(b, do_atom)),
|
||||
Name(t.tok().to_api()),
|
||||
Ph(ph.to_api()),
|
||||
S(p.clone(), b => mtreev_to_api(b, do_atom)),
|
||||
Slot(tk.0.clone()),
|
||||
} {
|
||||
MTok::Ref(r) => r.to_api(&mut sink),
|
||||
MTok::Done(t) => t.to_api(do_atom),
|
||||
MTok::Atom(a) => do_atom(a),
|
||||
})
|
||||
}
|
||||
pub fn at(self, pos: Pos) -> MTree<'a, A> { MTree { pos, tok: Arc::new(self) } }
|
||||
}
|
||||
|
||||
pub fn mtreev_from_api<'a, 'b, A>(
|
||||
api: impl IntoIterator<Item = &'b api::MacroTree>,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
api: impl IntoIterator<Item = &'b api::MacroTree>,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
) -> Vec<MTree<'a, A>> {
|
||||
api.into_iter().map(|api| MTree::from_api(api, do_atom)).collect_vec()
|
||||
api.into_iter().map(|api| MTree::from_api(api, do_atom)).collect_vec()
|
||||
}
|
||||
|
||||
pub fn mtreev_to_api<'a: 'b, 'b, A: 'b>(
|
||||
v: impl IntoIterator<Item = &'b MTree<'a, A>>,
|
||||
do_atom: &mut impl MacroAtomToApi<A>,
|
||||
v: impl IntoIterator<Item = &'b MTree<'a, A>>,
|
||||
do_atom: &mut impl MacroAtomToApi<A>,
|
||||
) -> Vec<api::MacroTree> {
|
||||
v.into_iter().map(|t| t.to_api(do_atom)).collect_vec()
|
||||
v.into_iter().map(|t| t.to_api(do_atom)).collect_vec()
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/// A shorthand for mapping over enums with identical structure. Used for converting between
|
||||
/// owned enums and the corresponding API enums that only differ in the type of their
|
||||
/// fields.
|
||||
///
|
||||
/// A shorthand for mapping over enums with identical structure. Used for
|
||||
/// converting between owned enums and the corresponding API enums that only
|
||||
/// differ in the type of their fields.
|
||||
///
|
||||
/// The basic form is
|
||||
/// ```ignore
|
||||
/// match_mapping!(self, ThisType => OtherType {
|
||||
@@ -78,7 +78,7 @@ macro_rules! match_mapping {
|
||||
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident () $value:expr , $($tail:tt)*) => {
|
||||
match_mapping!(@PAT_MUNCH $ctx ($($names)* $name) $($tail)*)
|
||||
};
|
||||
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident . $($tail:tt)*) => {
|
||||
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident . $($tail:tt)*) => {
|
||||
match_mapping!(@PAT_DOT_MUNCH $ctx ($($names)* $name) $($tail)*)
|
||||
};
|
||||
(@PAT_DOT_MUNCH $ctx:tt $names:tt , $($tail:tt)*) => {
|
||||
@@ -122,4 +122,4 @@ macro_rules! match_mapping {
|
||||
(@VAL_MUNCH ({} ($($prefix:tt)*)) ($( ( $name:ident $($value:tt)* ) )*) ) => {
|
||||
$($prefix)* { $( $name : $($value)* ),* }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,14 @@ use std::io;
|
||||
use orchid_api_traits::{Decode, Encode};
|
||||
|
||||
pub fn send_msg(write: &mut impl io::Write, msg: &[u8]) -> io::Result<()> {
|
||||
u32::try_from(msg.len()).unwrap().encode(write);
|
||||
write.write_all(msg)?;
|
||||
write.flush()
|
||||
u32::try_from(msg.len()).unwrap().encode(write);
|
||||
write.write_all(msg)?;
|
||||
write.flush()
|
||||
}
|
||||
|
||||
pub fn recv_msg(read: &mut impl io::Read) -> io::Result<Vec<u8>> {
|
||||
let len = u32::decode(read);
|
||||
let mut msg = vec![0u8; len as usize];
|
||||
read.read_exact(&mut msg)?;
|
||||
Ok(msg)
|
||||
let len = u32::decode(read);
|
||||
let mut msg = vec![0u8; len as usize];
|
||||
read.read_exact(&mut msg)?;
|
||||
Ok(msg)
|
||||
}
|
||||
+299
-299
@@ -12,11 +12,11 @@ use itertools::Itertools;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::interner::{intern, InternMarker, Tok};
|
||||
use crate::interner::{InternMarker, Tok, intern};
|
||||
|
||||
trait_set! {
|
||||
/// Traits that all name iterators should implement
|
||||
pub trait NameIter = Iterator<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
|
||||
/// Traits that all name iterators should implement
|
||||
pub trait NameIter = Iterator<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
|
||||
}
|
||||
|
||||
/// A borrowed name fragment which can be empty. See [VPath] for the owned
|
||||
@@ -25,129 +25,129 @@ trait_set! {
|
||||
#[repr(transparent)]
|
||||
pub struct PathSlice([Tok<String>]);
|
||||
impl PathSlice {
|
||||
/// Create a new [PathSlice]
|
||||
pub fn new(slice: &[Tok<String>]) -> &PathSlice {
|
||||
// SAFETY: This is ok because PathSlice is #[repr(transparent)]
|
||||
unsafe { &*(slice as *const [Tok<String>] as *const PathSlice) }
|
||||
}
|
||||
/// Convert to an owned name fragment
|
||||
pub fn to_vpath(&self) -> VPath { VPath(self.0.to_vec()) }
|
||||
/// Iterate over the tokens
|
||||
pub fn iter(&self) -> impl NameIter + '_ { self.into_iter() }
|
||||
/// Iterate over the segments
|
||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||
Box::new(self.0.iter().map(|s| s.as_str()))
|
||||
}
|
||||
/// Find the longest shared prefix of this name and another sequence
|
||||
pub fn coprefix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
|
||||
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
|
||||
}
|
||||
/// Find the longest shared suffix of this name and another sequence
|
||||
pub fn cosuffix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
|
||||
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
|
||||
}
|
||||
/// Remove another
|
||||
pub fn strip_prefix<'a>(&'a self, other: &PathSlice) -> Option<&'a PathSlice> {
|
||||
let shared = self.coprefix(other).len();
|
||||
(shared == other.len()).then_some(PathSlice::new(&self[shared..]))
|
||||
}
|
||||
/// Number of path segments
|
||||
pub fn len(&self) -> u16 { self.0.len().try_into().expect("Too long name!") }
|
||||
pub fn get<I: NameIndex>(&self, index: I) -> Option<&I::Output> { index.get(self) }
|
||||
/// Whether there are any path segments. In other words, whether this is a
|
||||
/// valid name
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
/// Obtain a reference to the held slice. With all indexing traits shadowed,
|
||||
/// this is better done explicitly
|
||||
pub fn as_slice(&self) -> &[Tok<String>] { self }
|
||||
/// Global empty path slice
|
||||
pub fn empty() -> &'static Self { PathSlice::new(&[]) }
|
||||
/// Create a new [PathSlice]
|
||||
pub fn new(slice: &[Tok<String>]) -> &PathSlice {
|
||||
// SAFETY: This is ok because PathSlice is #[repr(transparent)]
|
||||
unsafe { &*(slice as *const [Tok<String>] as *const PathSlice) }
|
||||
}
|
||||
/// Convert to an owned name fragment
|
||||
pub fn to_vpath(&self) -> VPath { VPath(self.0.to_vec()) }
|
||||
/// Iterate over the tokens
|
||||
pub fn iter(&self) -> impl NameIter + '_ { self.into_iter() }
|
||||
/// Iterate over the segments
|
||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||
Box::new(self.0.iter().map(|s| s.as_str()))
|
||||
}
|
||||
/// Find the longest shared prefix of this name and another sequence
|
||||
pub fn coprefix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
|
||||
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
|
||||
}
|
||||
/// Find the longest shared suffix of this name and another sequence
|
||||
pub fn cosuffix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
|
||||
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
|
||||
}
|
||||
/// Remove another
|
||||
pub fn strip_prefix<'a>(&'a self, other: &PathSlice) -> Option<&'a PathSlice> {
|
||||
let shared = self.coprefix(other).len();
|
||||
(shared == other.len()).then_some(PathSlice::new(&self[shared..]))
|
||||
}
|
||||
/// Number of path segments
|
||||
pub fn len(&self) -> u16 { self.0.len().try_into().expect("Too long name!") }
|
||||
pub fn get<I: NameIndex>(&self, index: I) -> Option<&I::Output> { index.get(self) }
|
||||
/// Whether there are any path segments. In other words, whether this is a
|
||||
/// valid name
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
/// Obtain a reference to the held slice. With all indexing traits shadowed,
|
||||
/// this is better done explicitly
|
||||
pub fn as_slice(&self) -> &[Tok<String>] { self }
|
||||
/// Global empty path slice
|
||||
pub fn empty() -> &'static Self { PathSlice::new(&[]) }
|
||||
}
|
||||
impl fmt::Debug for PathSlice {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
||||
}
|
||||
impl fmt::Display for PathSlice {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
}
|
||||
impl Borrow<[Tok<String>]> for PathSlice {
|
||||
fn borrow(&self) -> &[Tok<String>] { &self.0 }
|
||||
fn borrow(&self) -> &[Tok<String>] { &self.0 }
|
||||
}
|
||||
impl<'a> IntoIterator for &'a PathSlice {
|
||||
type IntoIter = Cloned<slice::Iter<'a, Tok<String>>>;
|
||||
type Item = Tok<String>;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.iter().cloned() }
|
||||
type IntoIter = Cloned<slice::Iter<'a, Tok<String>>>;
|
||||
type Item = Tok<String>;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.iter().cloned() }
|
||||
}
|
||||
|
||||
pub trait NameIndex {
|
||||
type Output: ?Sized;
|
||||
fn get(self, name: &PathSlice) -> Option<&Self::Output>;
|
||||
type Output: ?Sized;
|
||||
fn get(self, name: &PathSlice) -> Option<&Self::Output>;
|
||||
}
|
||||
impl<T: NameIndex> Index<T> for PathSlice {
|
||||
type Output = T::Output;
|
||||
fn index(&self, index: T) -> &Self::Output { index.get(self).expect("Index out of bounds") }
|
||||
type Output = T::Output;
|
||||
fn index(&self, index: T) -> &Self::Output { index.get(self).expect("Index out of bounds") }
|
||||
}
|
||||
|
||||
mod idx_impls {
|
||||
use std::ops;
|
||||
use std::ops;
|
||||
|
||||
use super::{conv_range, NameIndex, PathSlice};
|
||||
use crate::interner::Tok;
|
||||
use super::{NameIndex, PathSlice, conv_range};
|
||||
use crate::interner::Tok;
|
||||
|
||||
impl NameIndex for u16 {
|
||||
type Output = Tok<String>;
|
||||
fn get(self, name: &PathSlice) -> Option<&Self::Output> { name.0.get(self as usize) }
|
||||
}
|
||||
impl NameIndex for u16 {
|
||||
type Output = Tok<String>;
|
||||
fn get(self, name: &PathSlice) -> Option<&Self::Output> { name.0.get(self as usize) }
|
||||
}
|
||||
|
||||
impl NameIndex for ops::RangeFull {
|
||||
type Output = PathSlice;
|
||||
fn get(self, name: &PathSlice) -> Option<&Self::Output> { Some(name) }
|
||||
}
|
||||
impl NameIndex for ops::RangeFull {
|
||||
type Output = PathSlice;
|
||||
fn get(self, name: &PathSlice) -> Option<&Self::Output> { Some(name) }
|
||||
}
|
||||
|
||||
macro_rules! impl_range_index_for_pathslice {
|
||||
($range:ident) => {
|
||||
impl ops::Index<ops::$range<u16>> for PathSlice {
|
||||
type Output = Self;
|
||||
fn index(&self, index: ops::$range<u16>) -> &Self::Output {
|
||||
Self::new(&self.0[conv_range::<u16, usize>(index)])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_range_index_for_pathslice {
|
||||
($range:ident) => {
|
||||
impl ops::Index<ops::$range<u16>> for PathSlice {
|
||||
type Output = Self;
|
||||
fn index(&self, index: ops::$range<u16>) -> &Self::Output {
|
||||
Self::new(&self.0[conv_range::<u16, usize>(index)])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_range_index_for_pathslice!(RangeFrom);
|
||||
impl_range_index_for_pathslice!(RangeTo);
|
||||
impl_range_index_for_pathslice!(Range);
|
||||
impl_range_index_for_pathslice!(RangeInclusive);
|
||||
impl_range_index_for_pathslice!(RangeToInclusive);
|
||||
impl_range_index_for_pathslice!(RangeFrom);
|
||||
impl_range_index_for_pathslice!(RangeTo);
|
||||
impl_range_index_for_pathslice!(Range);
|
||||
impl_range_index_for_pathslice!(RangeInclusive);
|
||||
impl_range_index_for_pathslice!(RangeToInclusive);
|
||||
}
|
||||
|
||||
impl Deref for PathSlice {
|
||||
type Target = [Tok<String>];
|
||||
type Target = [Tok<String>];
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
impl Borrow<PathSlice> for [Tok<String>] {
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(self) }
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(self) }
|
||||
}
|
||||
impl<const N: usize> Borrow<PathSlice> for [Tok<String>; N] {
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
|
||||
}
|
||||
impl Borrow<PathSlice> for Vec<Tok<String>> {
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
|
||||
}
|
||||
pub fn conv_bound<T: Into<U> + Clone, U>(bound: Bound<&T>) -> Bound<U> {
|
||||
match bound {
|
||||
Bound::Included(i) => Bound::Included(i.clone().into()),
|
||||
Bound::Excluded(i) => Bound::Excluded(i.clone().into()),
|
||||
Bound::Unbounded => Bound::Unbounded,
|
||||
}
|
||||
match bound {
|
||||
Bound::Included(i) => Bound::Included(i.clone().into()),
|
||||
Bound::Excluded(i) => Bound::Excluded(i.clone().into()),
|
||||
Bound::Unbounded => Bound::Unbounded,
|
||||
}
|
||||
}
|
||||
pub fn conv_range<'a, T: Into<U> + Clone + 'a, U: 'a>(
|
||||
range: impl RangeBounds<T>,
|
||||
range: impl RangeBounds<T>,
|
||||
) -> (Bound<U>, Bound<U>) {
|
||||
(conv_bound(range.start_bound()), conv_bound(range.end_bound()))
|
||||
(conv_bound(range.start_bound()), conv_bound(range.end_bound()))
|
||||
}
|
||||
|
||||
/// A token path which may be empty. [VName] is the non-empty,
|
||||
@@ -155,90 +155,90 @@ pub fn conv_range<'a, T: Into<U> + Clone + 'a, U: 'a>(
|
||||
#[derive(Clone, Default, Hash, PartialEq, Eq)]
|
||||
pub struct VPath(pub Vec<Tok<String>>);
|
||||
impl VPath {
|
||||
/// Collect segments into a vector
|
||||
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(items.into_iter().collect())
|
||||
}
|
||||
/// Number of path segments
|
||||
pub fn len(&self) -> usize { self.0.len() }
|
||||
/// Whether there are any path segments. In other words, whether this is a
|
||||
/// valid name
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
/// Prepend some tokens to the path
|
||||
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(items.into_iter().chain(self.0).collect())
|
||||
}
|
||||
/// Append some tokens to the path
|
||||
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Partition the string by `::` namespace separators
|
||||
pub fn parse(s: &str) -> Self {
|
||||
Self(if s.is_empty() { vec![] } else { s.split("::").map(intern).collect() })
|
||||
}
|
||||
/// Walk over the segments
|
||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||
Box::new(self.0.iter().map(|s| s.as_str()))
|
||||
}
|
||||
/// Try to convert into non-empty version
|
||||
pub fn into_name(self) -> Result<VName, EmptyNameError> { VName::new(self.0) }
|
||||
/// Add a token to the path. Since now we know that it can't be empty, turn it
|
||||
/// into a name.
|
||||
pub fn name_with_prefix(self, name: Tok<String>) -> VName {
|
||||
VName(self.into_iter().chain([name]).collect())
|
||||
}
|
||||
/// Add a token to the beginning of the. Since now we know that it can't be
|
||||
/// empty, turn it into a name.
|
||||
pub fn name_with_suffix(self, name: Tok<String>) -> VName {
|
||||
VName([name].into_iter().chain(self).collect())
|
||||
}
|
||||
/// Collect segments into a vector
|
||||
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(items.into_iter().collect())
|
||||
}
|
||||
/// Number of path segments
|
||||
pub fn len(&self) -> usize { self.0.len() }
|
||||
/// Whether there are any path segments. In other words, whether this is a
|
||||
/// valid name
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
/// Prepend some tokens to the path
|
||||
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(items.into_iter().chain(self.0).collect())
|
||||
}
|
||||
/// Append some tokens to the path
|
||||
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Partition the string by `::` namespace separators
|
||||
pub fn parse(s: &str) -> Self {
|
||||
Self(if s.is_empty() { vec![] } else { s.split("::").map(intern).collect() })
|
||||
}
|
||||
/// Walk over the segments
|
||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||
Box::new(self.0.iter().map(|s| s.as_str()))
|
||||
}
|
||||
/// Try to convert into non-empty version
|
||||
pub fn into_name(self) -> Result<VName, EmptyNameError> { VName::new(self.0) }
|
||||
/// Add a token to the path. Since now we know that it can't be empty, turn it
|
||||
/// into a name.
|
||||
pub fn name_with_prefix(self, name: Tok<String>) -> VName {
|
||||
VName(self.into_iter().chain([name]).collect())
|
||||
}
|
||||
/// Add a token to the beginning of the. Since now we know that it can't be
|
||||
/// empty, turn it into a name.
|
||||
pub fn name_with_suffix(self, name: Tok<String>) -> VName {
|
||||
VName([name].into_iter().chain(self).collect())
|
||||
}
|
||||
|
||||
/// Convert a fs path to a vpath
|
||||
pub fn from_path(path: &Path) -> Option<(Self, bool)> {
|
||||
let to_vpath =
|
||||
|p: &Path| p.iter().map(|c| c.to_str().map(intern)).collect::<Option<_>>().map(VPath);
|
||||
match path.extension().map(|s| s.to_str()) {
|
||||
Some(Some("orc")) => Some((to_vpath(&path.with_extension(""))?, true)),
|
||||
None => Some((to_vpath(path)?, false)),
|
||||
Some(_) => None,
|
||||
}
|
||||
}
|
||||
/// Convert a fs path to a vpath
|
||||
pub fn from_path(path: &Path) -> Option<(Self, bool)> {
|
||||
let to_vpath =
|
||||
|p: &Path| p.iter().map(|c| c.to_str().map(intern)).collect::<Option<_>>().map(VPath);
|
||||
match path.extension().map(|s| s.to_str()) {
|
||||
Some(Some("orc")) => Some((to_vpath(&path.with_extension(""))?, true)),
|
||||
None => Some((to_vpath(path)?, false)),
|
||||
Some(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for VPath {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
||||
}
|
||||
impl fmt::Display for VPath {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
}
|
||||
impl FromIterator<Tok<String>> for VPath {
|
||||
fn from_iter<T: IntoIterator<Item = Tok<String>>>(iter: T) -> Self {
|
||||
Self(iter.into_iter().collect())
|
||||
}
|
||||
fn from_iter<T: IntoIterator<Item = Tok<String>>>(iter: T) -> Self {
|
||||
Self(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
impl IntoIterator for VPath {
|
||||
type Item = Tok<String>;
|
||||
type IntoIter = vec::IntoIter<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||
type Item = Tok<String>;
|
||||
type IntoIter = vec::IntoIter<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||
}
|
||||
impl Borrow<[Tok<String>]> for VPath {
|
||||
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
|
||||
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
|
||||
}
|
||||
impl Borrow<PathSlice> for VPath {
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
|
||||
}
|
||||
impl Deref for VPath {
|
||||
type Target = PathSlice;
|
||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||
type Target = PathSlice;
|
||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||
}
|
||||
|
||||
impl<T> Index<T> for VPath
|
||||
where PathSlice: Index<T>
|
||||
{
|
||||
type Output = <PathSlice as Index<T>>::Output;
|
||||
type Output = <PathSlice as Index<T>>::Output;
|
||||
|
||||
fn index(&self, index: T) -> &Self::Output { &Borrow::<PathSlice>::borrow(self)[index] }
|
||||
fn index(&self, index: T) -> &Self::Output { &Borrow::<PathSlice>::borrow(self)[index] }
|
||||
}
|
||||
|
||||
/// A mutable representation of a namespaced identifier of at least one segment.
|
||||
@@ -250,71 +250,71 @@ where PathSlice: Index<T>
|
||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||
pub struct VName(Vec<Tok<String>>);
|
||||
impl VName {
|
||||
/// Assert that the sequence isn't empty and wrap it in [VName] to represent
|
||||
/// this invariant
|
||||
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||
let data: Vec<_> = items.into_iter().collect();
|
||||
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
|
||||
}
|
||||
pub fn deintern(items: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
|
||||
Self::new(items.into_iter().map(Tok::from_api))
|
||||
}
|
||||
/// Unwrap the enclosed vector
|
||||
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
|
||||
/// Get a reference to the enclosed vector
|
||||
pub fn vec(&self) -> &Vec<Tok<String>> { &self.0 }
|
||||
/// Mutable access to the underlying vector. To ensure correct results, this
|
||||
/// must never be empty.
|
||||
pub fn vec_mut(&mut self) -> &mut Vec<Tok<String>> { &mut self.0 }
|
||||
/// Intern the name and return a [Sym]
|
||||
pub fn to_sym(&self) -> Sym { Sym(intern(&self.0[..])) }
|
||||
/// If this name has only one segment, return it
|
||||
pub fn as_root(&self) -> Option<Tok<String>> { self.0.iter().exactly_one().ok().cloned() }
|
||||
/// Prepend the segments to this name
|
||||
#[must_use = "This is a pure function"]
|
||||
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(items.into_iter().chain(self.0).collect())
|
||||
}
|
||||
/// Append the segments to this name
|
||||
#[must_use = "This is a pure function"]
|
||||
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Read a `::` separated namespaced name
|
||||
pub fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s)) }
|
||||
pub fn literal(s: &'static str) -> Self { Self::parse(s).expect("empty literal !?") }
|
||||
/// Obtain an iterator over the segments of the name
|
||||
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ { self.0.iter().cloned() }
|
||||
/// Assert that the sequence isn't empty and wrap it in [VName] to represent
|
||||
/// this invariant
|
||||
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||
let data: Vec<_> = items.into_iter().collect();
|
||||
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
|
||||
}
|
||||
pub fn deintern(items: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
|
||||
Self::new(items.into_iter().map(Tok::from_api))
|
||||
}
|
||||
/// Unwrap the enclosed vector
|
||||
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
|
||||
/// Get a reference to the enclosed vector
|
||||
pub fn vec(&self) -> &Vec<Tok<String>> { &self.0 }
|
||||
/// Mutable access to the underlying vector. To ensure correct results, this
|
||||
/// must never be empty.
|
||||
pub fn vec_mut(&mut self) -> &mut Vec<Tok<String>> { &mut self.0 }
|
||||
/// Intern the name and return a [Sym]
|
||||
pub fn to_sym(&self) -> Sym { Sym(intern(&self.0[..])) }
|
||||
/// If this name has only one segment, return it
|
||||
pub fn as_root(&self) -> Option<Tok<String>> { self.0.iter().exactly_one().ok().cloned() }
|
||||
/// Prepend the segments to this name
|
||||
#[must_use = "This is a pure function"]
|
||||
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(items.into_iter().chain(self.0).collect())
|
||||
}
|
||||
/// Append the segments to this name
|
||||
#[must_use = "This is a pure function"]
|
||||
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Read a `::` separated namespaced name
|
||||
pub fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s)) }
|
||||
pub fn literal(s: &'static str) -> Self { Self::parse(s).expect("empty literal !?") }
|
||||
/// Obtain an iterator over the segments of the name
|
||||
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ { self.0.iter().cloned() }
|
||||
}
|
||||
impl fmt::Debug for VName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
||||
}
|
||||
impl fmt::Display for VName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
}
|
||||
impl IntoIterator for VName {
|
||||
type Item = Tok<String>;
|
||||
type IntoIter = vec::IntoIter<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||
type Item = Tok<String>;
|
||||
type IntoIter = vec::IntoIter<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||
}
|
||||
impl<T> Index<T> for VName
|
||||
where PathSlice: Index<T>
|
||||
{
|
||||
type Output = <PathSlice as Index<T>>::Output;
|
||||
type Output = <PathSlice as Index<T>>::Output;
|
||||
|
||||
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
||||
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
||||
}
|
||||
impl Borrow<[Tok<String>]> for VName {
|
||||
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
|
||||
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
|
||||
}
|
||||
impl Borrow<PathSlice> for VName {
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
|
||||
}
|
||||
impl Deref for VName {
|
||||
type Target = PathSlice;
|
||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||
type Target = PathSlice;
|
||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||
}
|
||||
|
||||
/// Error produced when a non-empty name [VName] or [Sym] is constructed with an
|
||||
@@ -322,10 +322,10 @@ impl Deref for VName {
|
||||
#[derive(Debug, Copy, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct EmptyNameError;
|
||||
impl TryFrom<&[Tok<String>]> for VName {
|
||||
type Error = EmptyNameError;
|
||||
fn try_from(value: &[Tok<String>]) -> Result<Self, Self::Error> {
|
||||
Self::new(value.iter().cloned())
|
||||
}
|
||||
type Error = EmptyNameError;
|
||||
fn try_from(value: &[Tok<String>]) -> Result<Self, Self::Error> {
|
||||
Self::new(value.iter().cloned())
|
||||
}
|
||||
}
|
||||
|
||||
/// An interned representation of a namespaced identifier.
|
||||
@@ -336,94 +336,94 @@ impl TryFrom<&[Tok<String>]> for VName {
|
||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Sym(Tok<Vec<Tok<String>>>);
|
||||
impl Sym {
|
||||
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
|
||||
/// represent this invariant
|
||||
pub fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||
let items = v.into_iter().collect_vec();
|
||||
Self::from_tok(intern(&items[..]))
|
||||
}
|
||||
/// Read a `::` separated namespaced name.
|
||||
pub fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(intern(&VName::parse(s)?.into_vec()[..])))
|
||||
}
|
||||
/// Assert that a token isn't empty, and wrap it in a [Sym]
|
||||
pub fn from_tok(t: Tok<Vec<Tok<String>>>) -> Result<Self, EmptyNameError> {
|
||||
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
|
||||
}
|
||||
/// Grab the interner token
|
||||
pub fn tok(&self) -> Tok<Vec<Tok<String>>> { self.0.clone() }
|
||||
/// Get a number unique to this name suitable for arbitrary ordering.
|
||||
pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() }
|
||||
/// Extern the sym for editing
|
||||
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
|
||||
pub fn from_api(marker: api::TStrv) -> Sym {
|
||||
Self::from_tok(Tok::from_api(marker)).expect("Empty sequence found for serialized Sym")
|
||||
}
|
||||
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
|
||||
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
|
||||
/// represent this invariant
|
||||
pub fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||
let items = v.into_iter().collect_vec();
|
||||
Self::from_tok(intern(&items[..]))
|
||||
}
|
||||
/// Read a `::` separated namespaced name.
|
||||
pub fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(intern(&VName::parse(s)?.into_vec()[..])))
|
||||
}
|
||||
/// Assert that a token isn't empty, and wrap it in a [Sym]
|
||||
pub fn from_tok(t: Tok<Vec<Tok<String>>>) -> Result<Self, EmptyNameError> {
|
||||
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
|
||||
}
|
||||
/// Grab the interner token
|
||||
pub fn tok(&self) -> Tok<Vec<Tok<String>>> { self.0.clone() }
|
||||
/// Get a number unique to this name suitable for arbitrary ordering.
|
||||
pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() }
|
||||
/// Extern the sym for editing
|
||||
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
|
||||
pub fn from_api(marker: api::TStrv) -> Sym {
|
||||
Self::from_tok(Tok::from_api(marker)).expect("Empty sequence found for serialized Sym")
|
||||
}
|
||||
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
|
||||
}
|
||||
impl fmt::Debug for Sym {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Sym({self})") }
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Sym({self})") }
|
||||
}
|
||||
impl fmt::Display for Sym {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.str_iter().join("::"))
|
||||
}
|
||||
}
|
||||
impl<T> Index<T> for Sym
|
||||
where PathSlice: Index<T>
|
||||
{
|
||||
type Output = <PathSlice as Index<T>>::Output;
|
||||
type Output = <PathSlice as Index<T>>::Output;
|
||||
|
||||
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
||||
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
||||
}
|
||||
impl Borrow<[Tok<String>]> for Sym {
|
||||
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
|
||||
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
|
||||
}
|
||||
impl Borrow<PathSlice> for Sym {
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
|
||||
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
|
||||
}
|
||||
impl Deref for Sym {
|
||||
type Target = PathSlice;
|
||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||
type Target = PathSlice;
|
||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||
}
|
||||
|
||||
/// An abstraction over tokenized vs non-tokenized names so that they can be
|
||||
/// handled together in datastructures. The names can never be empty
|
||||
#[allow(clippy::len_without_is_empty)] // never empty
|
||||
pub trait NameLike:
|
||||
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<PathSlice>
|
||||
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<PathSlice>
|
||||
{
|
||||
/// Convert into held slice
|
||||
fn as_slice(&self) -> &[Tok<String>] { Borrow::<PathSlice>::borrow(self) }
|
||||
/// Get iterator over tokens
|
||||
fn iter(&self) -> impl NameIter + '_ { self.as_slice().iter().cloned() }
|
||||
/// Get iterator over string segments
|
||||
fn str_iter(&self) -> impl Iterator<Item = &'_ str> + '_ {
|
||||
self.as_slice().iter().map(|t| t.as_str())
|
||||
}
|
||||
/// Fully resolve the name for printing
|
||||
#[must_use]
|
||||
fn to_strv(&self) -> Vec<String> { self.iter().map(|s| s.to_string()).collect() }
|
||||
/// Format the name as an approximate filename
|
||||
fn as_src_path(&self) -> String { format!("{}.orc", self.iter().join("/")) }
|
||||
/// Return the number of segments in the name
|
||||
fn len(&self) -> NonZeroUsize {
|
||||
NonZeroUsize::try_from(self.iter().count()).expect("NameLike never empty")
|
||||
}
|
||||
/// Like slice's `split_first` except we know that it always returns Some
|
||||
fn split_first(&self) -> (Tok<String>, &PathSlice) {
|
||||
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
||||
(foot.clone(), PathSlice::new(torso))
|
||||
}
|
||||
/// Like slice's `split_last` except we know that it always returns Some
|
||||
fn split_last(&self) -> (Tok<String>, &PathSlice) {
|
||||
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
||||
(foot.clone(), PathSlice::new(torso))
|
||||
}
|
||||
/// Get the first element
|
||||
fn first(&self) -> Tok<String> { self.split_first().0 }
|
||||
/// Get the last element
|
||||
fn last(&self) -> Tok<String> { self.split_last().0 }
|
||||
/// Convert into held slice
|
||||
fn as_slice(&self) -> &[Tok<String>] { Borrow::<PathSlice>::borrow(self) }
|
||||
/// Get iterator over tokens
|
||||
fn iter(&self) -> impl NameIter + '_ { self.as_slice().iter().cloned() }
|
||||
/// Get iterator over string segments
|
||||
fn str_iter(&self) -> impl Iterator<Item = &'_ str> + '_ {
|
||||
self.as_slice().iter().map(|t| t.as_str())
|
||||
}
|
||||
/// Fully resolve the name for printing
|
||||
#[must_use]
|
||||
fn to_strv(&self) -> Vec<String> { self.iter().map(|s| s.to_string()).collect() }
|
||||
/// Format the name as an approximate filename
|
||||
fn as_src_path(&self) -> String { format!("{}.orc", self.iter().join("/")) }
|
||||
/// Return the number of segments in the name
|
||||
fn len(&self) -> NonZeroUsize {
|
||||
NonZeroUsize::try_from(self.iter().count()).expect("NameLike never empty")
|
||||
}
|
||||
/// Like slice's `split_first` except we know that it always returns Some
|
||||
fn split_first(&self) -> (Tok<String>, &PathSlice) {
|
||||
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
||||
(foot.clone(), PathSlice::new(torso))
|
||||
}
|
||||
/// Like slice's `split_last` except we know that it always returns Some
|
||||
fn split_last(&self) -> (Tok<String>, &PathSlice) {
|
||||
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
||||
(foot.clone(), PathSlice::new(torso))
|
||||
}
|
||||
/// Get the first element
|
||||
fn first(&self) -> Tok<String> { self.split_first().0 }
|
||||
/// Get the last element
|
||||
fn last(&self) -> Tok<String> { self.split_last().0 }
|
||||
}
|
||||
|
||||
impl NameLike for Sym {}
|
||||
@@ -492,35 +492,35 @@ macro_rules! path_slice {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::borrow::Borrow;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use super::{PathSlice, Sym, VName};
|
||||
use crate::interner::{intern, Tok};
|
||||
use crate::name::VPath;
|
||||
use super::{PathSlice, Sym, VName};
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::name::VPath;
|
||||
|
||||
#[test]
|
||||
fn recur() {
|
||||
let myname = vname!(foo::bar);
|
||||
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||
let _borrowed_pathslice: &PathSlice = myname.borrow();
|
||||
let _deref_pathslice: &PathSlice = &myname;
|
||||
let _as_slice_out: &[Tok<String>] = myname.as_slice();
|
||||
}
|
||||
#[test]
|
||||
fn recur() {
|
||||
let myname = vname!(foo::bar);
|
||||
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||
let _borrowed_pathslice: &PathSlice = myname.borrow();
|
||||
let _deref_pathslice: &PathSlice = &myname;
|
||||
let _as_slice_out: &[Tok<String>] = myname.as_slice();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn literals() {
|
||||
assert_eq!(
|
||||
sym!(foo::bar::baz),
|
||||
Sym::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vname!(foo::bar::baz),
|
||||
VName::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
|
||||
);
|
||||
assert_eq!(vpath!(foo::bar::baz), VPath::new([intern("foo"), intern("bar"), intern("baz")]));
|
||||
assert_eq!(
|
||||
path_slice!(foo::bar::baz),
|
||||
PathSlice::new(&[intern("foo"), intern("bar"), intern("baz")])
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn literals() {
|
||||
assert_eq!(
|
||||
sym!(foo::bar::baz),
|
||||
Sym::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vname!(foo::bar::baz),
|
||||
VName::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
|
||||
);
|
||||
assert_eq!(vpath!(foo::bar::baz), VPath::new([intern("foo"), intern("bar"), intern("baz")]));
|
||||
assert_eq!(
|
||||
path_slice!(foo::bar::baz),
|
||||
PathSlice::new(&[intern("foo"), intern("bar"), intern("baz")])
|
||||
);
|
||||
}
|
||||
}
|
||||
+124
-124
@@ -1,131 +1,131 @@
|
||||
use std::num::IntErrorKind;
|
||||
use std::ops::Range;
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
use ordered_float::NotNan;
|
||||
use rust_decimal::Decimal;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::error::{mk_err, OrcErr};
|
||||
use crate::error::{OrcErr, mk_err};
|
||||
use crate::intern;
|
||||
use crate::location::Pos;
|
||||
|
||||
/// A number, either floating point or unsigned int, parsed by Orchid.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Numeric {
|
||||
/// A nonnegative integer
|
||||
Uint(u64),
|
||||
/// A binary float other than NaN
|
||||
Float(NotNan<f64>),
|
||||
/// A decimal number
|
||||
Decimal(Decimal),
|
||||
/// A nonnegative integer
|
||||
Uint(u64),
|
||||
/// A binary float other than NaN
|
||||
Float(NotNan<f64>),
|
||||
/// A decimal number
|
||||
Decimal(Decimal),
|
||||
}
|
||||
impl Numeric {
|
||||
pub fn decimal(num: i64, scale: u32) -> Self { Self::Decimal(Decimal::new(num, scale)) }
|
||||
pub fn float(value: f64) -> Self { Self::Float(NotNan::new(value).unwrap()) }
|
||||
pub fn to_f64(self) -> NotNan<f64> {
|
||||
match self {
|
||||
Self::Float(f) => f,
|
||||
Self::Decimal(d) => {
|
||||
let f = d.to_f64().expect("This is apparently always possible");
|
||||
NotNan::new(f).expect("decimal was nan")
|
||||
},
|
||||
Self::Uint(i) => NotNan::new(i as f64).expect("int cannot be NaN"),
|
||||
}
|
||||
}
|
||||
pub fn decimal(num: i64, scale: u32) -> Self { Self::Decimal(Decimal::new(num, scale)) }
|
||||
pub fn float(value: f64) -> Self { Self::Float(NotNan::new(value).unwrap()) }
|
||||
pub fn to_f64(self) -> NotNan<f64> {
|
||||
match self {
|
||||
Self::Float(f) => f,
|
||||
Self::Decimal(d) => {
|
||||
let f = d.to_f64().expect("This is apparently always possible");
|
||||
NotNan::new(f).expect("decimal was nan")
|
||||
},
|
||||
Self::Uint(i) => NotNan::new(i as f64).expect("int cannot be NaN"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rasons why [parse_num] might fail. See [NumError].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum NumErrorKind {
|
||||
/// The literal describes [f64::NAN]
|
||||
NaN,
|
||||
/// Some integer appearing in the literal overflows [usize]
|
||||
Overflow,
|
||||
/// A character that isn't a digit in the given base was found
|
||||
InvalidDigit,
|
||||
/// The literal describes [f64::NAN]
|
||||
NaN,
|
||||
/// Some integer appearing in the literal overflows [usize]
|
||||
Overflow,
|
||||
/// A character that isn't a digit in the given base was found
|
||||
InvalidDigit,
|
||||
}
|
||||
impl NumErrorKind {
|
||||
fn from_int(kind: &IntErrorKind) -> Self {
|
||||
match kind {
|
||||
IntErrorKind::InvalidDigit => Self::InvalidDigit,
|
||||
IntErrorKind::NegOverflow | IntErrorKind::PosOverflow => Self::Overflow,
|
||||
_ => panic!("Impossible error condition"),
|
||||
}
|
||||
}
|
||||
fn from_int(kind: &IntErrorKind) -> Self {
|
||||
match kind {
|
||||
IntErrorKind::InvalidDigit => Self::InvalidDigit,
|
||||
IntErrorKind::NegOverflow | IntErrorKind::PosOverflow => Self::Overflow,
|
||||
_ => panic!("Impossible error condition"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error produced by [parse_num]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct NumError {
|
||||
/// Location
|
||||
pub range: Range<usize>,
|
||||
/// Reason
|
||||
pub kind: NumErrorKind,
|
||||
/// Location
|
||||
pub range: Range<usize>,
|
||||
/// Reason
|
||||
pub kind: NumErrorKind,
|
||||
}
|
||||
|
||||
pub fn num_to_err(NumError { kind, range }: NumError, offset: u32) -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "Failed to parse number"),
|
||||
match kind {
|
||||
NumErrorKind::NaN => "NaN emerged during parsing",
|
||||
NumErrorKind::InvalidDigit => "non-digit character encountered",
|
||||
NumErrorKind::Overflow => "The number being described is too large or too accurate",
|
||||
},
|
||||
[Pos::Range(offset + range.start as u32..offset + range.end as u32).into()],
|
||||
)
|
||||
mk_err(
|
||||
intern!(str: "Failed to parse number"),
|
||||
match kind {
|
||||
NumErrorKind::NaN => "NaN emerged during parsing",
|
||||
NumErrorKind::InvalidDigit => "non-digit character encountered",
|
||||
NumErrorKind::Overflow => "The number being described is too large or too accurate",
|
||||
},
|
||||
[Pos::Range(offset + range.start as u32..offset + range.end as u32).into()],
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse a numbre literal out of text
|
||||
pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
|
||||
let overflow_err = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow };
|
||||
let (radix, noprefix, pos) = (string.strip_prefix("0x").map(|s| (16u8, s, 2)))
|
||||
.or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2)))
|
||||
.or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2)))
|
||||
.unwrap_or((10u8, string, 0));
|
||||
// identity
|
||||
let (base, exponent) = match noprefix.split_once('p') {
|
||||
Some((b, e)) => {
|
||||
let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1));
|
||||
(b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32)
|
||||
},
|
||||
None => (noprefix, 0),
|
||||
};
|
||||
match base.split_once('.') {
|
||||
None => {
|
||||
let base_usize = int_parse(base, radix, pos)?;
|
||||
if let Ok(pos_exp) = u32::try_from(exponent) {
|
||||
if let Some(radical) = u64::from(radix).checked_pow(pos_exp) {
|
||||
let number = base_usize.checked_mul(radical).ok_or(overflow_err)?;
|
||||
return Ok(Numeric::Uint(number));
|
||||
}
|
||||
}
|
||||
let f = (base_usize as f64) * (radix as f64).powi(exponent);
|
||||
let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN };
|
||||
Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?))
|
||||
},
|
||||
Some((whole, part)) => {
|
||||
let whole_n = int_parse(whole, radix, pos)?;
|
||||
let part_n = int_parse(part, radix, pos + whole.len() + 1)?;
|
||||
let scale = part.chars().filter(|c| *c != '_').count() as u32;
|
||||
if radix == 10 {
|
||||
let mut scaled_unit = Decimal::ONE;
|
||||
(scaled_unit.set_scale(scale))
|
||||
.map_err(|_| NumError { range: 0..string.len(), kind: NumErrorKind::Overflow })?;
|
||||
Ok(Numeric::Decimal(Decimal::from(whole_n) + scaled_unit * Decimal::from(part_n)))
|
||||
} else {
|
||||
let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32));
|
||||
let f = real_val * (radix as f64).powi(exponent);
|
||||
Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN")))
|
||||
}
|
||||
},
|
||||
}
|
||||
let overflow_err = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow };
|
||||
let (radix, noprefix, pos) = (string.strip_prefix("0x").map(|s| (16u8, s, 2)))
|
||||
.or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2)))
|
||||
.or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2)))
|
||||
.unwrap_or((10u8, string, 0));
|
||||
// identity
|
||||
let (base, exponent) = match noprefix.split_once('p') {
|
||||
Some((b, e)) => {
|
||||
let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1));
|
||||
(b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32)
|
||||
},
|
||||
None => (noprefix, 0),
|
||||
};
|
||||
match base.split_once('.') {
|
||||
None => {
|
||||
let base_usize = int_parse(base, radix, pos)?;
|
||||
if let Ok(pos_exp) = u32::try_from(exponent) {
|
||||
if let Some(radical) = u64::from(radix).checked_pow(pos_exp) {
|
||||
let number = base_usize.checked_mul(radical).ok_or(overflow_err)?;
|
||||
return Ok(Numeric::Uint(number));
|
||||
}
|
||||
}
|
||||
let f = (base_usize as f64) * (radix as f64).powi(exponent);
|
||||
let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN };
|
||||
Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?))
|
||||
},
|
||||
Some((whole, part)) => {
|
||||
let whole_n = int_parse(whole, radix, pos)?;
|
||||
let part_n = int_parse(part, radix, pos + whole.len() + 1)?;
|
||||
let scale = part.chars().filter(|c| *c != '_').count() as u32;
|
||||
if radix == 10 {
|
||||
let mut scaled_unit = Decimal::ONE;
|
||||
(scaled_unit.set_scale(scale))
|
||||
.map_err(|_| NumError { range: 0..string.len(), kind: NumErrorKind::Overflow })?;
|
||||
Ok(Numeric::Decimal(Decimal::from(whole_n) + scaled_unit * Decimal::from(part_n)))
|
||||
} else {
|
||||
let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32));
|
||||
let f = real_val * (radix as f64).powi(exponent);
|
||||
Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN")))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn int_parse(s: &str, radix: u8, start: usize) -> Result<u64, NumError> {
|
||||
let s = s.chars().filter(|c| *c != '_').collect::<String>();
|
||||
let range = start..(start + s.len());
|
||||
u64::from_str_radix(&s, radix as u32)
|
||||
.map_err(|e| NumError { range, kind: NumErrorKind::from_int(e.kind()) })
|
||||
let s = s.chars().filter(|c| *c != '_').collect::<String>();
|
||||
let range = start..(start + s.len());
|
||||
u64::from_str_radix(&s, radix as u32)
|
||||
.map_err(|e| NumError { range, kind: NumErrorKind::from_int(e.kind()) })
|
||||
}
|
||||
|
||||
/// Filter for characters that can appear in numbers
|
||||
@@ -136,42 +136,42 @@ pub fn numstart(c: char) -> bool { c.is_ascii_digit() }
|
||||
/// Print a number as a base-16 floating point literal
|
||||
#[must_use]
|
||||
pub fn print_nat16(num: NotNan<f64>) -> String {
|
||||
if *num == 0.0 {
|
||||
return "0x0".to_string();
|
||||
} else if num.is_infinite() {
|
||||
return match num.is_sign_positive() {
|
||||
true => "Infinity".to_string(),
|
||||
false => "-Infinity".to_string(),
|
||||
};
|
||||
} else if num.is_nan() {
|
||||
return "NaN".to_string();
|
||||
}
|
||||
let exp = num.log(16.0).floor();
|
||||
let man = *num / 16_f64.powf(exp);
|
||||
format!("0x{man}p{exp:.0}")
|
||||
if *num == 0.0 {
|
||||
return "0x0".to_string();
|
||||
} else if num.is_infinite() {
|
||||
return match num.is_sign_positive() {
|
||||
true => "Infinity".to_string(),
|
||||
false => "-Infinity".to_string(),
|
||||
};
|
||||
} else if num.is_nan() {
|
||||
return "NaN".to_string();
|
||||
}
|
||||
let exp = num.log(16.0).floor();
|
||||
let man = *num / 16_f64.powf(exp);
|
||||
format!("0x{man}p{exp:.0}")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{parse_num, Numeric};
|
||||
use super::{Numeric, parse_num};
|
||||
|
||||
#[test]
|
||||
fn just_ints() {
|
||||
let test = |s, n| assert_eq!(parse_num(s), Ok(Numeric::Uint(n)));
|
||||
test("12345", 12345);
|
||||
test("0xcafebabe", 0xcafebabe);
|
||||
test("0o751", 0o751);
|
||||
test("0b111000111", 0b111000111);
|
||||