use an off-the-shelf crate for maelstrom node.

The echo server is basically copied from the example for the crate, but it's
nothing special.
This commit is contained in:
Joe Ardent 2024-05-17 15:46:10 -07:00
parent 98412c147b
commit 4fecd6cc9a
10 changed files with 33 additions and 263 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
target/
store/

109
Cargo.lock generated
View File

@ -1,109 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "gg-echo"
version = "0.0.1"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "maelstrom-node"
version = "0.0.1"
[[package]]
name = "maelstrom-protocol"
version = "0.0.1"
dependencies = [
"serde",
"serde_json",
"serde_repr",
]
[[package]]
name = "proc-macro2"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_repr"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

View File

@ -1,5 +1,5 @@
[workspace]
members = ["gg-echo", "maelstrom-protocol", "maelstrom-node"]
members = ["gg-echo"]
resolver = "2"
[workspace.package]

View File

@ -1,8 +1 @@
Working through the [Fly.io distributed systems challenge](https://fly.io/dist-sys/), in Rust.
The project is organized as a Cargo workspace. The `maelstrom-*` crates are libraries that provide
the equivalent functionality as the [Maelstrom
Go](https://pkg.go.dev/github.com/jepsen-io/maelstrom/demo/go) package that is provided by
Fly.io. The protocol crate especially is stand-alone and just provides the
serializable/deserializable Rust types for Maelstrom messages. The node crate handles IO, while the
`gg-*` crates are bin crates that implement the named challenge.

View File

@ -5,3 +5,6 @@ version.workspace = true
authors.workspace = true
[dependencies]
async-trait = "0.1.80"
maelstrom-node = "0.1.6"
tokio = { version = "1.37.0", default-features = false, features = ["io-util", "io-std", "rt-multi-thread", "macros"] }

View File

@ -1,3 +1,29 @@
fn main() {
println!("Hello, world!");
use async_trait::async_trait;
use maelstrom::protocol::Message;
use maelstrom::{done, Node, Result, Runtime};
use std::sync::Arc;
#[tokio::main]
async fn main() {
let handler = Arc::new(Handler::default());
let _ = Runtime::new()
.with_handler(handler)
.run()
.await
.unwrap_or_default();
}
#[derive(Clone, Default)]
struct Handler {}
#[async_trait]
impl Node for Handler {
async fn process(&self, runtime: Runtime, req: Message) -> Result<()> {
if req.get_type() == "echo" {
let echo = req.body.clone().with_type("echo_ok");
return runtime.reply(req, echo).await;
}
done(runtime, req)
}
}

View File

@ -1,7 +0,0 @@
[package]
name = "maelstrom-node"
edition = "2021"
version.workspace = true
authors.workspace = true
[dependencies]

View File

@ -1,14 +0,0 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

View File

@ -1,10 +0,0 @@
[package]
name = "maelstrom-protocol"
edition = "2021"
version.workspace = true
authors.workspace = true
[dependencies]
serde = { version = "1", default-features = false, features = ["derive"] }
serde_json = { version = "1", default-features = false, features = ["std"] }
serde_repr = "0.1"

View File

@ -1,113 +0,0 @@
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message<P> {
src: String,
dest: String,
body: Body<P>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Body<P> {
#[serde(rename = "type")]
pub typ: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub msg_id: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub in_reply_to: Option<u64>,
#[serde(flatten)]
pub payload: P,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ErrorCode {
Definite(DefiniteError),
Indefinite(IndefiniteError),
}
#[derive(Debug, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u64)]
pub enum DefiniteError {
NodeNotFound = 2,
NotSupported = 10,
TemporarilyUnavailable = 11,
MalformedRequest = 12,
Abort = 14,
KeyNotFound = 20,
KeyAlreadyExists = 21,
PreconditionFailed = 22,
TxnConflict = 30,
}
#[derive(Debug, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u64)]
pub enum IndefiniteError {
Timeout = 0,
Crash = 13,
}
pub fn init_ok(msg_id: u64, in_reply_to: Option<u64>) -> Body<payloads::InitOk> {
Body {
typ: "init_ok".to_string(),
msg_id: Some(msg_id),
in_reply_to,
payload: payloads::InitOk,
}
}
pub fn error(
msg_id: u64,
in_reply_to: Option<u64>,
code: ErrorCode,
text: Option<&str>,
) -> Body<payloads::ErrorResp> {
Body {
typ: "error".to_string(),
msg_id: Some(msg_id),
in_reply_to,
payload: payloads::ErrorResp {
code,
text: text.map(|s| s.to_string()),
},
}
}
pub mod payloads {
use crate::ErrorCode;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
pub trait Payload:
std::fmt::Debug + Sized + Send + Clone + Serialize + DeserializeOwned
{
}
impl<T> Payload for T where T: std::fmt::Debug + Sized + Send + Clone + Serialize + DeserializeOwned {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Init {
pub node_id: String,
pub node_ids: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitOk;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorResp {
pub code: ErrorCode,
pub text: Option<String>,
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn error_codes() {
let ec = ErrorCode::Definite(DefiniteError::Abort);
let e = serde_json::to_string(&ec).unwrap();
assert_eq!(&e, "14");
}
}