Checkpoint for gRPC implementation
This commit is contained in:
Generated
+353
-2
@@ -383,15 +383,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@@ -407,6 +425,17 @@ version = "0.3.32"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@@ -426,6 +455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-macro",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"slab",
|
"slab",
|
||||||
@@ -442,6 +472,19 @@ dependencies = [
|
|||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasip2",
|
||||||
|
"wasip3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
@@ -478,6 +521,15 @@ version = "0.12.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.17.1"
|
version = "0.17.1"
|
||||||
@@ -490,6 +542,25 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hello-world"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"prost",
|
||||||
|
"roto-runtime",
|
||||||
|
"roto-tonic",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
"tonic",
|
||||||
|
"tonic-build",
|
||||||
|
"tower 0.4.13",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -596,6 +667,12 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "id-arena"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.3"
|
version = "1.9.3"
|
||||||
@@ -614,6 +691,8 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.17.1",
|
"hashbrown 0.17.1",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -684,12 +763,24 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "leb128fmt"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.186"
|
version = "0.2.186"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
@@ -734,6 +825,12 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multimap"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
@@ -790,6 +887,16 @@ version = "2.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.12"
|
version = "1.1.12"
|
||||||
@@ -868,6 +975,16 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prettyplease"
|
||||||
|
version = "0.2.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.106"
|
version = "1.0.106"
|
||||||
@@ -887,6 +1004,26 @@ dependencies = [
|
|||||||
"prost-derive",
|
"prost-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-build"
|
||||||
|
version = "0.13.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"itertools",
|
||||||
|
"log",
|
||||||
|
"multimap",
|
||||||
|
"once_cell",
|
||||||
|
"petgraph",
|
||||||
|
"prettyplease",
|
||||||
|
"prost",
|
||||||
|
"prost-types",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prost-derive"
|
name = "prost-derive"
|
||||||
version = "0.13.5"
|
version = "0.13.5"
|
||||||
@@ -900,6 +1037,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-types"
|
||||||
|
version = "0.13.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16"
|
||||||
|
dependencies = [
|
||||||
|
"prost",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "protos"
|
name = "protos"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -913,6 +1059,12 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
@@ -940,7 +1092,7 @@ version = "0.6.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1039,6 +1191,19 @@ dependencies = [
|
|||||||
"tonic",
|
"tonic",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
@@ -1060,6 +1225,12 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.228"
|
||||||
@@ -1168,6 +1339,19 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"getrandom 0.4.2",
|
||||||
|
"once_cell",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "test_grpc_project"
|
name = "test_grpc_project"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1273,6 +1457,20 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tonic-build"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11"
|
||||||
|
dependencies = [
|
||||||
|
"prettyplease",
|
||||||
|
"proc-macro2",
|
||||||
|
"prost-build",
|
||||||
|
"prost-types",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
@@ -1325,6 +1523,7 @@ version = "0.1.44"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
@@ -1362,6 +1561,12 @@ version = "1.0.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -1393,6 +1598,24 @@ version = "0.11.1+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip2"
|
||||||
|
version = "1.0.3+wasi-0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen 0.57.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip3"
|
||||||
|
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen 0.51.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.120"
|
version = "0.2.120"
|
||||||
@@ -1438,6 +1661,40 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-encoder"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
||||||
|
dependencies = [
|
||||||
|
"leb128fmt",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-metadata"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"wasm-encoder",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmparser"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"hashbrown 0.15.5",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.97"
|
version = "0.3.97"
|
||||||
@@ -1545,6 +1802,100 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rust-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.57.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-core"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"heck",
|
||||||
|
"wit-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rust"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"heck",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"prettyplease",
|
||||||
|
"syn",
|
||||||
|
"wasm-metadata",
|
||||||
|
"wit-bindgen-core",
|
||||||
|
"wit-component",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rust-macro"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"prettyplease",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wit-bindgen-core",
|
||||||
|
"wit-bindgen-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-component"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bitflags",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"wasm-encoder",
|
||||||
|
"wasm-metadata",
|
||||||
|
"wasmparser",
|
||||||
|
"wit-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-parser"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"id-arena",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"log",
|
||||||
|
"semver",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"unicode-xid",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.48"
|
version = "0.8.48"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ members = [
|
|||||||
"protos",
|
"protos",
|
||||||
"benches",
|
"benches",
|
||||||
"roto-tonic", "test_grpc_project",
|
"roto-tonic", "test_grpc_project",
|
||||||
|
"examples/hello_world",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = [
|
exclude = [
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ Instead of deserializing binary protobuf data into Rust structs, roto scans a me
|
|||||||
construction — recording the byte offset of each field — then reads fields on demand directly from
|
construction — recording the byte offset of each field — then reads fields on demand directly from
|
||||||
the original bytes. No heap allocation, no data copying, no full deserialization upfront.
|
the original bytes. No heap allocation, no data copying, no full deserialization upfront.
|
||||||
|
|
||||||
Writing works the same way: you provide a fixed buffer and a builder writes fields directly into it,
|
It also provides a first-class integration with the `tonic` gRPC framework via the `roto-tonic` crate,
|
||||||
returning a slice of the bytes written.
|
enabling zero-allocation request/response processing.
|
||||||
|
|
||||||
|
Writing works the same way: you provide a fixed buffer (or a `bytes::BufMut`) and a builder writes
|
||||||
|
fields directly into it, returning a slice of the bytes written.
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
@@ -28,10 +31,15 @@ This will generate a file, src/hackers.rs.
|
|||||||
|
|
||||||
## Generated code
|
## Generated code
|
||||||
|
|
||||||
For each protobuf message roto generates two types:
|
For each protobuf message roto generates three types:
|
||||||
|
|
||||||
- **Reader struct** `MessageName<'a>` — borrows the original byte slice, zero-copy.
|
- **Reader struct** `MessageName<'a>` — borrows the original byte slice, zero-copy.
|
||||||
- **Builder struct** `MessageNameBuilder<'b>` — writes into a caller-provided `&mut [u8]`.
|
- **Builder struct** `MessageNameBuilder<'b>` — writes into a caller-provided `&mut [u8]` or `BufMut`.
|
||||||
|
- **Owned struct** `OwnedMessageName` — owns the byte buffer and implements `RotoOwned`, providing a bridge to the `Reader`.
|
||||||
|
|
||||||
|
For each protobuf service, roto generates:
|
||||||
|
|
||||||
|
- **Service Trait** `ServiceName` — a `tonic`-compatible async trait for gRPC service implementations.
|
||||||
|
|
||||||
Nested message types are placed in a `pub mod message_name { ... }` module (snake_case of the
|
Nested message types are placed in a `pub mod message_name { ... }` module (snake_case of the
|
||||||
parent message name) within the same generated file.
|
parent message name) within the same generated file.
|
||||||
@@ -314,12 +322,4 @@ The goal is to validate roto's implementation against the Proto3 specification.
|
|||||||
### Unsupported Features
|
### Unsupported Features
|
||||||
|
|
||||||
- **Reserved Fields**: `reserved` statements are ignored.
|
- **Reserved Fields**: `reserved` statements are ignored.
|
||||||
- **Services**: `service` and `rpc` definitions are ignored.
|
|
||||||
- **Options**: Field and message options are ignored.
|
- **Options**: Field and message options are ignored.
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
- [x] Analyze `roto/codegen` to determine which protobuf constructs are supported during code generation.
|
|
||||||
- [x] Analyze `roto/runtime` to determine which wire types and protobuf types are supported during reading and writing.
|
|
||||||
- [x] Compare findings with the Proto3 spec (https://protobuf.dev/reference/protobuf/proto3-spec/).
|
|
||||||
- [x] Document supported and unsupported features in the README.
|
|
||||||
|
|||||||
@@ -439,14 +439,15 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
|
|||||||
output.push_str("}\n\n");
|
output.push_str("}\n\n");
|
||||||
|
|
||||||
output.push_str(&format!("impl roto_runtime::RotoOwned for Owned{} {{\n", msg_name));
|
output.push_str(&format!("impl roto_runtime::RotoOwned for Owned{} {{\n", msg_name));
|
||||||
|
output.push_str(&format!(" type Reader<'a> = {}<'a>;\n", msg_name));
|
||||||
output.push_str(&format!(" fn reader(&self) -> {}<'_> {{\n", msg_name));
|
output.push_str(&format!(" fn reader(&self) -> {}<'_> {{\n", msg_name));
|
||||||
output.push_str(&format!(" {}::new(&self.data).expect(\"failed to create reader\")\n", msg_name));
|
output.push_str(&format!(" {}::new(&self.data).expect(\"failed to create reader\")\n", msg_name));
|
||||||
output.push_str(" }\n");
|
output.push_str(" }\n");
|
||||||
output.push_str("}\n\n");
|
output.push_str("}\n\n");
|
||||||
|
|
||||||
output.push_str(&format!("impl roto_runtime::RotoMessage for Owned{} {{\n", msg_name));
|
output.push_str(&format!("impl roto_runtime::RotoMessage for Owned{} {{\n", msg_name));
|
||||||
output.push_str(" fn decode(buf: bytes::Bytes) -> Self {\n");
|
output.push_str(" fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {\n");
|
||||||
output.push_str(&format!(" Owned{} {{ data: buf }}\n", msg_name));
|
output.push_str(&format!(" Ok(Owned{} {{ data: buf }})\n", msg_name));
|
||||||
output.push_str(" }\n\n");
|
output.push_str(" }\n\n");
|
||||||
output.push_str(" fn bytes(&self) -> bytes::Bytes {\n");
|
output.push_str(" fn bytes(&self) -> bytes::Bytes {\n");
|
||||||
output.push_str(" self.data.clone()\n");
|
output.push_str(" self.data.clone()\n");
|
||||||
@@ -675,7 +676,7 @@ fn write_service(svc_proto: &ServiceDescriptorProto, output: &mut String) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
" async fn {}(&self, request: {}) -> Result<{}, Status>;\n",
|
" async fn {}(&self, request: {}) -> std::result::Result<{}, Status>;\n",
|
||||||
method_name, req_type, resp_type
|
method_name, req_type, resp_type
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ fn test_generated_code_builds() {
|
|||||||
let cargo_toml_content =
|
let cargo_toml_content =
|
||||||
fs::read_to_string(&cargo_toml_path).expect("Failed to read Cargo.toml");
|
fs::read_to_string(&cargo_toml_path).expect("Failed to read Cargo.toml");
|
||||||
let updated_cargo_toml = format!(
|
let updated_cargo_toml = format!(
|
||||||
"{}\n\nroto-codegen = {{ path = \"..\" }}\nroto-runtime = {{ path = \"../../runtime\" }}\n\n[workspace]\n",
|
"{}\n\nroto-codegen = {{ path = \"..\" }}\nroto-runtime = {{ path = \"../../runtime\" }}\nbytes = \"1.0\"\ntonic = \"0.12\"\ntokio-stream = \"0.1\"\n\n[workspace]\n",
|
||||||
cargo_toml_content
|
cargo_toml_content
|
||||||
);
|
);
|
||||||
fs::write(cargo_toml_path, updated_cargo_toml).expect("Failed to write Cargo.toml");
|
fs::write(cargo_toml_path, updated_cargo_toml).expect("Failed to write Cargo.toml");
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ fn test_map_generated_code_builds() {
|
|||||||
let cargo_toml_content =
|
let cargo_toml_content =
|
||||||
fs::read_to_string(&cargo_toml_path).expect("Failed to read Cargo.toml");
|
fs::read_to_string(&cargo_toml_path).expect("Failed to read Cargo.toml");
|
||||||
let updated_cargo_toml = format!(
|
let updated_cargo_toml = format!(
|
||||||
"{}\n\nroto-codegen = {{ path = \"..\" }}\nroto-runtime = {{ path = \"../../runtime\" }}\n\n[workspace]\n",
|
"{}\n\nroto-codegen = {{ path = \"..\" }}\nroto-runtime = {{ path = \"../../runtime\" }}\nbytes = \"1.0\"\ntonic = \"0.12\"\ntokio-stream = \"0.1\"\n\n[workspace]\n",
|
||||||
cargo_toml_content
|
cargo_toml_content
|
||||||
);
|
);
|
||||||
fs::write(cargo_toml_path, updated_cargo_toml).expect("Failed to write Cargo.toml");
|
fs::write(cargo_toml_path, updated_cargo_toml).expect("Failed to write Cargo.toml");
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
[package]
|
||||||
|
name = "hello-world"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "server"
|
||||||
|
path = "src/bin/server.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "client"
|
||||||
|
path = "src/bin/client.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
roto-runtime = { path = "../../runtime" }
|
||||||
|
roto-tonic = { path = "../../roto-tonic" }
|
||||||
|
tonic = "0.12"
|
||||||
|
tokio = { version = "1.38", features = ["full"] }
|
||||||
|
tokio-stream = "0.1"
|
||||||
|
bytes = "1.7"
|
||||||
|
prost = "0.13"
|
||||||
|
tower = "0.4"
|
||||||
|
futures-util = "0.3"
|
||||||
|
http-body-util = "0.1"
|
||||||
|
http = "1.1"
|
||||||
|
http-body = "1.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tonic-build = "0.12"
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
fn main() {
|
||||||
|
let proto_file = "proto/hello.proto";
|
||||||
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
let dest_path = std::path::Path::new(&out_dir).join("hello.rs");
|
||||||
|
|
||||||
|
// Find the protoc-gen-roto binary
|
||||||
|
// In a real scenario, this should be passed as an environment variable or found in PATH
|
||||||
|
// For this example, we'll try to find it in the target directory
|
||||||
|
let target_dir = std::env::current_dir().unwrap().join("../../target/debug");
|
||||||
|
let plugin_path = target_dir.join("protoc-gen-roto");
|
||||||
|
|
||||||
|
if !plugin_path.exists() {
|
||||||
|
panic!("protoc-gen-roto plugin not found at {:?}", plugin_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = std::process::Command::new("protoc")
|
||||||
|
.arg(format!("--plugin=protoc-gen-roto={}", plugin_path.display()))
|
||||||
|
.arg(format!("--roto_out={}", out_dir))
|
||||||
|
.arg(format!("--roto_opt=src=proto")) // Assuming the plugin handles this or we just pass it
|
||||||
|
.arg(proto_file)
|
||||||
|
.status()
|
||||||
|
.expect("Failed to execute protoc");
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
panic!("protoc failed with status {}", status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package hello;
|
||||||
|
|
||||||
|
service HelloWorldService {
|
||||||
|
rpc HelloWorld (HelloRequest) returns (HelloResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message HelloRequest {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HelloResponse {
|
||||||
|
string message = 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
// @generated by protoc-gen-roto — do not edit
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
|
||||||
|
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator};
|
||||||
|
use std::str;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use tonic::{Request, Response, Status};
|
||||||
|
use tokio_stream::Stream;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct HelloRequest<'a> {
|
||||||
|
accessor: roto_runtime::ProtoAccessor<'a>,
|
||||||
|
name_offset: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HelloRequest<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
|
||||||
|
let accessor = roto_runtime::ProtoAccessor::new(data)?;
|
||||||
|
let mut name_offset = None;
|
||||||
|
for item in accessor.fields() {
|
||||||
|
let (offset, tag, _) = item?;
|
||||||
|
if tag.field_number == 1 { name_offset = Some(offset); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
accessor,
|
||||||
|
name_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> roto_runtime::Result<&'a str> {
|
||||||
|
let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> {
|
||||||
|
self.name().or(Ok(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_name(&self) -> bool { self.name_offset.is_some() }
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HelloRequestBuilder<'b> {
|
||||||
|
builder: roto_runtime::ProtoBuilder<'b>,
|
||||||
|
name_written: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> HelloRequestBuilder<'b> {
|
||||||
|
pub fn builder(buf: &mut [u8]) -> HelloRequestBuilder<'_> {
|
||||||
|
HelloRequestBuilder {
|
||||||
|
builder: roto_runtime::ProtoBuilder::new(buf),
|
||||||
|
name_written: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(mut self, value: &str) -> roto_runtime::Result<Self> {
|
||||||
|
self.builder.write_string(1, value)?;
|
||||||
|
self.name_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &HelloRequest<'_>) -> roto_runtime::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.name_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
|
||||||
|
self.builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OwnedHelloRequest {
|
||||||
|
pub data: bytes::Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl roto_runtime::RotoOwned for OwnedHelloRequest {
|
||||||
|
type Reader<'a> = HelloRequest<'a>;
|
||||||
|
fn reader(&self) -> HelloRequest<'_> {
|
||||||
|
HelloRequest::new(&self.data).expect("failed to create reader")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl roto_runtime::RotoMessage for OwnedHelloRequest {
|
||||||
|
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
|
||||||
|
Ok(OwnedHelloRequest { data: buf })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bytes(&self) -> bytes::Bytes {
|
||||||
|
self.data.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HelloResponse<'a> {
|
||||||
|
accessor: roto_runtime::ProtoAccessor<'a>,
|
||||||
|
message_offset: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HelloResponse<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
|
||||||
|
let accessor = roto_runtime::ProtoAccessor::new(data)?;
|
||||||
|
let mut message_offset = None;
|
||||||
|
for item in accessor.fields() {
|
||||||
|
let (offset, tag, _) = item?;
|
||||||
|
if tag.field_number == 1 { message_offset = Some(offset); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
accessor,
|
||||||
|
message_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message(&self) -> roto_runtime::Result<&'a str> {
|
||||||
|
let offset = self.message_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message_or_default(&self) -> roto_runtime::Result<&'a str> {
|
||||||
|
self.message().or(Ok(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_message(&self) -> bool { self.message_offset.is_some() }
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HelloResponseBuilder<'b> {
|
||||||
|
builder: roto_runtime::ProtoBuilder<'b>,
|
||||||
|
message_written: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> HelloResponseBuilder<'b> {
|
||||||
|
pub fn builder(buf: &mut [u8]) -> HelloResponseBuilder<'_> {
|
||||||
|
HelloResponseBuilder {
|
||||||
|
builder: roto_runtime::ProtoBuilder::new(buf),
|
||||||
|
message_written: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message(mut self, value: &str) -> roto_runtime::Result<Self> {
|
||||||
|
self.builder.write_string(1, value)?;
|
||||||
|
self.message_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &HelloResponse<'_>) -> roto_runtime::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.message_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
|
||||||
|
self.builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OwnedHelloResponse {
|
||||||
|
pub data: bytes::Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl roto_runtime::RotoOwned for OwnedHelloResponse {
|
||||||
|
type Reader<'a> = HelloResponse<'a>;
|
||||||
|
fn reader(&self) -> HelloResponse<'_> {
|
||||||
|
HelloResponse::new(&self.data).expect("failed to create reader")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl roto_runtime::RotoMessage for OwnedHelloResponse {
|
||||||
|
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
|
||||||
|
Ok(OwnedHelloResponse { data: buf })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bytes(&self) -> bytes::Bytes {
|
||||||
|
self.data.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tonic::async_trait]
|
||||||
|
pub trait HelloWorldService: Send + Sync + 'static {
|
||||||
|
async fn hello_world(&self, request: Request<OwnedHelloRequest>) -> std::result::Result<Response<OwnedHelloResponse>, Status>;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
use tonic::Request;
|
||||||
|
use roto_tonic::RotoCodec;
|
||||||
|
use hello::{HelloWorldService, OwnedHelloRequest, OwnedHelloResponse};
|
||||||
|
use roto_runtime::RotoOwned;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
use tower::Service;
|
||||||
|
|
||||||
|
pub mod hello {
|
||||||
|
include!("../../proto/hello.rs");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReadyService<S>(S);
|
||||||
|
|
||||||
|
impl<S, Req> Service<Req> for ReadyService<S>
|
||||||
|
where
|
||||||
|
S: Service<Req>,
|
||||||
|
{
|
||||||
|
type Response = S::Response;
|
||||||
|
type Error = S::Error;
|
||||||
|
type Future = S::Future;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, req: Req) -> S::Future {
|
||||||
|
self.0.call(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let channel = tonic::transport::Channel::from_static("http://[::1]:50051")
|
||||||
|
.connect()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let ready_channel = ReadyService(channel);
|
||||||
|
let mut client = tonic::client::Grpc::new(ready_channel);
|
||||||
|
|
||||||
|
// We need to specify the method path. For HelloWorldService/HelloWorld, it is "/hello.HelloWorldService/HelloWorld"
|
||||||
|
let mut buf = vec![0u8; 1024];
|
||||||
|
let slice = hello::HelloRequestBuilder::builder(&mut buf)
|
||||||
|
.name("Roto").unwrap()
|
||||||
|
.finish().unwrap();
|
||||||
|
|
||||||
|
let request = OwnedHelloRequest {
|
||||||
|
data: bytes::Bytes::copy_from_slice(slice),
|
||||||
|
};
|
||||||
|
|
||||||
|
// In tonic's Grpc client, we specify the codec separately.
|
||||||
|
let response = client
|
||||||
|
.unary(
|
||||||
|
Request::new(request),
|
||||||
|
http::uri::PathAndQuery::from_static("/hello.HelloWorldService/HelloWorld"),
|
||||||
|
RotoCodec::<OwnedHelloResponse, OwnedHelloRequest>::default(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let response_msg: OwnedHelloResponse = response.into_inner();
|
||||||
|
let reader = response_msg.reader();
|
||||||
|
println!("Server responded: {}", reader.message().unwrap_or("No message"));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tonic::{transport::Server, Request, Response, Status};
|
||||||
|
use roto_tonic::RotoCodec;
|
||||||
|
use hello::{HelloWorldService, OwnedHelloRequest, OwnedHelloResponse};
|
||||||
|
use tower::Service;
|
||||||
|
use bytes::{Bytes, Buf, BufMut};
|
||||||
|
use tonic::body::BoxBody;
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
use roto_runtime::{RotoOwned, RotoMessage};
|
||||||
|
use http_body_util::BodyExt;
|
||||||
|
use http_body::Body;
|
||||||
|
|
||||||
|
pub mod hello {
|
||||||
|
include!("../../proto/hello.rs");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct MyHelloWorld {}
|
||||||
|
|
||||||
|
#[tonic::async_trait]
|
||||||
|
impl HelloWorldService for MyHelloWorld {
|
||||||
|
async fn hello_world(
|
||||||
|
&self,
|
||||||
|
request: Request<OwnedHelloRequest>,
|
||||||
|
) -> Result<Response<OwnedHelloResponse>, Status> {
|
||||||
|
let req = request.into_inner();
|
||||||
|
let reader = req.reader();
|
||||||
|
let name = reader.name().unwrap_or("Unknown");
|
||||||
|
|
||||||
|
let mut buf = vec![0u8; 1024];
|
||||||
|
let slice = hello::HelloResponseBuilder::builder(&mut buf)
|
||||||
|
.message(&format!("Hello {}!", name)).unwrap()
|
||||||
|
.finish().unwrap();
|
||||||
|
|
||||||
|
let reply = OwnedHelloResponse {
|
||||||
|
data: bytes::Bytes::copy_from_slice(slice),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Tonic Glue ---
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HelloWorldServer {
|
||||||
|
inner: Arc<MyHelloWorld>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HelloWorldServer {
|
||||||
|
pub fn new(inner: MyHelloWorld) -> Self {
|
||||||
|
Self { inner: Arc::new(inner) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl tonic::server::NamedService for HelloWorldServer {
|
||||||
|
const NAME: &'static str = "hello.HelloWorldService";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StatusBody(Option<Bytes>);
|
||||||
|
|
||||||
|
impl Body for StatusBody {
|
||||||
|
type Data = Bytes;
|
||||||
|
type Error = Status;
|
||||||
|
|
||||||
|
fn poll_frame(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
|
||||||
|
if let Some(data) = self.0.take() {
|
||||||
|
Poll::Ready(Some(Ok(http_body::Frame::data(data))))
|
||||||
|
} else {
|
||||||
|
Poll::Ready(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Service<http::Request<BoxBody>> for HelloWorldServer {
|
||||||
|
type Response = http::Response<BoxBody>;
|
||||||
|
type Error = std::convert::Infallible;
|
||||||
|
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, req: http::Request<BoxBody>) -> Self::Future {
|
||||||
|
let inner = self.inner.clone();
|
||||||
|
println!("Server received request: {} {}", req.method(), req.uri());
|
||||||
|
|
||||||
|
Box::pin(async move {
|
||||||
|
let body = req.into_body();
|
||||||
|
let bytes_vec = body.collect().await.map_err(|e| {
|
||||||
|
println!("Body collect error: {}", e);
|
||||||
|
panic!("Body collect error: {}", e);
|
||||||
|
})?.to_bytes();
|
||||||
|
println!("Collected body bytes: {} bytes", bytes_vec.len());
|
||||||
|
|
||||||
|
if bytes_vec.len() < 5 {
|
||||||
|
println!("Body too short: {} bytes", bytes_vec.len());
|
||||||
|
let res_body = BoxBody::new(StatusBody(Some(Bytes::from(vec![0, 0, 0, 0, 0]))));
|
||||||
|
return Ok(http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(res_body)
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = &bytes_vec[5..];
|
||||||
|
println!("Decoding request from {} bytes", data.len());
|
||||||
|
let request_msg = match OwnedHelloRequest::decode(Bytes::copy_from_slice(data)) {
|
||||||
|
Ok(msg) => msg,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Decode error: {}", e);
|
||||||
|
let res_body = BoxBody::new(StatusBody(Some(Bytes::from(vec![0, 0, 0, 0, 0]))));
|
||||||
|
return Ok(http::Response::builder().status(200).body(res_body).unwrap());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Request decoded successfully");
|
||||||
|
let response = match inner.hello_world(Request::new(request_msg)).await {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Service error: {}", e);
|
||||||
|
let res_body = BoxBody::new(StatusBody(Some(Bytes::from(vec![0, 0, 0, 0, 0]))));
|
||||||
|
return Ok(http::Response::builder().status(200).body(res_body).unwrap());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let response_msg = response.into_inner();
|
||||||
|
let response_bytes = response_msg.bytes();
|
||||||
|
println!("Service responded with {} bytes", response_bytes.len());
|
||||||
|
|
||||||
|
let mut res_buf = vec![0u8; 5 + response_bytes.len()];
|
||||||
|
res_buf[0] = 0;
|
||||||
|
let len = response_bytes.len() as u32;
|
||||||
|
res_buf[1..5].copy_from_slice(&len.to_be_bytes());
|
||||||
|
res_buf[5..].copy_from_slice(&response_bytes);
|
||||||
|
|
||||||
|
let res_body = BoxBody::new(StatusBody(Some(Bytes::from(res_buf))));
|
||||||
|
Ok(http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("content-type", "application/grpc")
|
||||||
|
.body(res_body)
|
||||||
|
.unwrap())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let addr: std::net::SocketAddr = "[::1]:50051".parse()?;
|
||||||
|
let hello = MyHelloWorld::default();
|
||||||
|
|
||||||
|
println!("Server listening on {}", addr);
|
||||||
|
|
||||||
|
Server::builder()
|
||||||
|
.add_service(HelloWorldServer::new(hello))
|
||||||
|
.serve(addr)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user