diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..fca193c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,42 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "capnp" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1087195be8d0ddd607f1e1b7d55dd808c24195213ca505cac2de127f0a35b674" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "capnpc" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f1cd4f042d6725da6245bde08c9e7c74f6fcb2d8bd5e0378e57991be8d711d8" +dependencies = [ + "capnp", +] + +[[package]] +name = "embedded-io" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" + +[[package]] +name = "show_from_stdin" +version = "0.1.0" +dependencies = [ + "types", +] + +[[package]] +name = "types" +version = "0.1.0" +dependencies = [ + "capnp", + "capnpc", +] diff --git a/Cargo.toml b/Cargo.toml index 4b41d67..f415d93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ resolver = "3" members = [ "crates/types", - "crates/applications/show_hello_world_from_stdin", + "crates/applications/show_from_stdin", ] [workspace.package] diff --git a/crates/applications/show_hello_world_from_stdin/Cargo.toml b/crates/applications/show_from_stdin/Cargo.toml similarity index 78% rename from crates/applications/show_hello_world_from_stdin/Cargo.toml rename to crates/applications/show_from_stdin/Cargo.toml index ae17867..0ce3171 100644 --- a/crates/applications/show_hello_world_from_stdin/Cargo.toml +++ b/crates/applications/show_from_stdin/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "show_hello_world_from_stdin" +name = "show_from_stdin" version = "0.1.0" edition.workspace = true license-file.workspace = true diff --git a/crates/applications/show_from_stdin/src/main.rs b/crates/applications/show_from_stdin/src/main.rs new file mode 100644 index 0000000..342fe09 --- /dev/null +++ b/crates/applications/show_from_stdin/src/main.rs @@ -0,0 +1,34 @@ +use types::capnp_projection_backend::CapnpPackedProjectionBackend; +use types::Message; + +pub struct Application { + projection_backend: CapnpPackedProjectionBackend, +} + +impl Application { + pub fn new() -> Self { + Self { projection_backend: CapnpPackedProjectionBackend } + } + + pub fn run_and_exit_with_process_status_code(&self) -> i32 { + match self + .projection_backend + .from_stdin::() + { + Ok(message) => { + println!("{}", message.text().as_str()); + 0 + } + Err(error) => { + eprintln!("{}", error.message()); + 2 + } + } + } +} + +fn main() { + let application = Application::new(); + let process_status_code = application.run_and_exit_with_process_status_code(); + std::process::exit(process_status_code); +} diff --git a/crates/applications/show_hello_world_from_stdin/src/main.rs b/crates/applications/show_hello_world_from_stdin/src/main.rs deleted file mode 100644 index 93bb435..0000000 --- a/crates/applications/show_hello_world_from_stdin/src/main.rs +++ /dev/null @@ -1,35 +0,0 @@ -use types::capnp_projection_backend::CapnpPackedProjectionBackendObject; -use types::HelloWorldObject; - -pub struct ShowHelloWorldFromStdinApplicationObject { - projection_backend_object: CapnpPackedProjectionBackendObject, -} - -impl ShowHelloWorldFromStdinApplicationObject { - pub fn new() -> Self { - Self { projection_backend_object: CapnpPackedProjectionBackendObject } - } - - pub fn run_and_exit_with_process_status_code(&self) -> i32 { - match self - .projection_backend_object - .read_object_from_stdin_as_packed_capnp::() - { - Ok(hello_world_object) => { - let text = hello_world_object.hello_world_utf8_text_object().hello_world_utf8_text(); - println!("{text}"); - 0 - } - Err(error_object) => { - eprintln!("{}", error_object.capnp_error_string()); - 2 - } - } - } -} - -fn main() { - let application_object = ShowHelloWorldFromStdinApplicationObject::new(); - let process_status_code = application_object.run_and_exit_with_process_status_code(); - std::process::exit(process_status_code); -} diff --git a/crates/types/build.rs b/crates/types/build.rs index 1ee7dfa..a0e1419 100644 --- a/crates/types/build.rs +++ b/crates/types/build.rs @@ -1,6 +1,6 @@ fn main() { capnpc::CompilerCommand::new() - .file("schema/hello_world.capnp") + .file("schema/message.capnp") .run() .expect("Cap’n Proto schema compilation must succeed."); } diff --git a/crates/types/schema/hello_world.capnp b/crates/types/schema/hello_world.capnp deleted file mode 100644 index bba3a47..0000000 --- a/crates/types/schema/hello_world.capnp +++ /dev/null @@ -1,5 +0,0 @@ -@0xb9d0dfb7a7c9a3a1; - -struct HelloWorld { - helloWorldUtf8Text @0 :Text; -} diff --git a/crates/types/schema/message.capnp b/crates/types/schema/message.capnp new file mode 100644 index 0000000..6fc265c --- /dev/null +++ b/crates/types/schema/message.capnp @@ -0,0 +1,5 @@ +@0xb9d0dfb7a7c9a3a1; + +struct Message { + text @0 :Text; +} diff --git a/crates/types/src/capnp_projection_backend.rs b/crates/types/src/capnp_projection_backend.rs index ce228d7..b3a118f 100644 --- a/crates/types/src/capnp_projection_backend.rs +++ b/crates/types/src/capnp_projection_backend.rs @@ -9,39 +9,39 @@ use capnp::serialize_packed; use crate::sajban_representation_codec::SajbanProjectionCodec; /// A projection backend object that converts between packed Cap’n Proto bytes and domain objects. -pub struct CapnpPackedProjectionBackendObject; +pub struct CapnpPackedProjectionBackend; -impl CapnpPackedProjectionBackendObject { - pub fn read_object_from_stdin_as_packed_capnp( +impl CapnpPackedProjectionBackend { + pub fn from_stdin( &self, - ) -> Result { + ) -> Result { let stdin = std::io::stdin(); let mut locked_stdin = stdin.lock(); let reader = serialize_packed::read_message(&mut locked_stdin, ReaderOptions::new()) - .map_err(CapnpPackedProjectionBackendErrorObject::new_from_capnp_error)?; + .map_err(CapnpPackedProjectionBackendError::new)?; let root = reader .get_root::>() - .map_err(CapnpPackedProjectionBackendErrorObject::new_from_capnp_error)?; + .map_err(CapnpPackedProjectionBackendError::new)?; Ok(T::read_from_projection(root)) } - pub fn write_object_to_packed_capnp_bytes( + pub fn to_bytes( &self, - object: &T, + value: &T, init_root: fn(&mut Builder) -> T::ProjectionBuilder<'_>, - ) -> Result, CapnpPackedProjectionBackendErrorObject> { + ) -> Result, CapnpPackedProjectionBackendError> { let mut message_builder: Builder = Builder::new_default(); { let builder = init_root(&mut message_builder); - object.write_to_projection(builder); + value.write_to_projection(builder); } let mut output_bytes: Vec = Vec::new(); serialize_packed::write_message(&mut output_bytes, &message_builder) - .map_err(CapnpPackedProjectionBackendErrorObject::new_from_capnp_error)?; + .map_err(CapnpPackedProjectionBackendError::new)?; Ok(output_bytes) } @@ -49,16 +49,16 @@ impl CapnpPackedProjectionBackendObject { /// An explicit error object that avoids returning naked standard-library error types at the boundary. #[derive(Debug)] -pub struct CapnpPackedProjectionBackendErrorObject { - capnp_error_string: String, +pub struct CapnpPackedProjectionBackendError { + message: String, } -impl CapnpPackedProjectionBackendErrorObject { - pub fn new_from_capnp_error(error: capnp::Error) -> Self { - Self { capnp_error_string: error.to_string() } +impl CapnpPackedProjectionBackendError { + pub fn new(error: capnp::Error) -> Self { + Self { message: error.to_string() } } - pub fn capnp_error_string(&self) -> &str { - &self.capnp_error_string + pub fn message(&self) -> &str { + &self.message } } diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index d3566f5..7c27940 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -8,70 +8,62 @@ pub mod sajban_representation_codec; #[allow(dead_code)] pub(crate) mod generated_capnp { - include!(concat!(env!("OUT_DIR"), "/hello_world_capnp.rs")); + include!(concat!(env!("OUT_DIR"), "/message_capnp.rs")); } use crate::sajban_representation_codec::{SajbanProjectionCodec, SajbanProjectionSchemaIdentity}; /// A domain object whose meaning is carried by explicit fields rather than positional primitives. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct HelloWorldObject { - hello_world_utf8_text_object: HelloWorldUtf8TextObject, +pub struct Message { + text: Text, } -impl HelloWorldObject { - /// Constructs a HelloWorldObject from a text object, preserving semantic meaning as an object boundary. - pub fn new_with_hello_world_utf8_text_object( - hello_world_utf8_text_object: HelloWorldUtf8TextObject, - ) -> Self { - Self { hello_world_utf8_text_object } +impl Message { + /// Constructs a message from a text object, preserving semantic meaning as an object boundary. + pub fn new(text: Text) -> Self { + Self { text } } /// Provides access to the contained text object. - pub fn hello_world_utf8_text_object(&self) -> &HelloWorldUtf8TextObject { - &self.hello_world_utf8_text_object + pub fn text(&self) -> &Text { + &self.text } } /// A text wrapper object that prevents meaning from collapsing into a naked standard-library primitive. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct HelloWorldUtf8TextObject { - hello_world_utf8_text: String, +pub struct Text { + value: String, } -impl HelloWorldUtf8TextObject { - pub fn new_with_hello_world_utf8_text(hello_world_utf8_text: String) -> Self { - Self { hello_world_utf8_text } +impl Text { + pub fn new(value: String) -> Self { + Self { value } } - pub fn hello_world_utf8_text(&self) -> &str { - &self.hello_world_utf8_text + pub fn as_str(&self) -> &str { + &self.value } } -impl SajbanProjectionSchemaIdentity for HelloWorldObject { +impl SajbanProjectionSchemaIdentity for Message { fn sajban_projection_type_name() -> &'static str { - "HelloWorld" + "Message" } } -impl SajbanProjectionCodec for HelloWorldObject { - type ProjectionReader<'a> = generated_capnp::hello_world::Reader<'a>; - type ProjectionBuilder<'a> = generated_capnp::hello_world::Builder<'a>; +impl SajbanProjectionCodec for Message { + type ProjectionReader<'a> = generated_capnp::message::Reader<'a>; + type ProjectionBuilder<'a> = generated_capnp::message::Builder<'a>; fn read_from_projection(reader: Self::ProjectionReader<'_>) -> Self { - let hello_world_utf8_text_object = - HelloWorldUtf8TextObject::new_with_hello_world_utf8_text( - reader - .get_hello_world_utf8_text() - .unwrap_or("") - .to_string(), - ); + let text = Text::new(reader.get_text().unwrap_or("").to_string()); - Self::new_with_hello_world_utf8_text_object(hello_world_utf8_text_object) + Self::new(text) } fn write_to_projection(&self, mut builder: Self::ProjectionBuilder<'_>) { - builder.set_hello_world_utf8_text(self.hello_world_utf8_text_object.hello_world_utf8_text()); + builder.set_text(self.text.as_str()); } } diff --git a/crates/types/tests/hello_world_text_projection_round_trip.rs b/crates/types/tests/text_projection_round_trip.rs similarity index 74% rename from crates/types/tests/hello_world_text_projection_round_trip.rs rename to crates/types/tests/text_projection_round_trip.rs index bf221b1..656388b 100644 --- a/crates/types/tests/hello_world_text_projection_round_trip.rs +++ b/crates/types/tests/text_projection_round_trip.rs @@ -1,27 +1,21 @@ use std::io::Write; use std::process::{Command, Stdio}; -use types::capnp_projection_backend::CapnpPackedProjectionBackendObject; -use types::sajban_representation_codec::SajbanProjectionCodec; -use types::HelloWorldObject; +pub struct TextProjectionRoundTripTest; -pub struct HelloWorldTextProjectionRoundTripTestObject; +impl TextProjectionRoundTripTest { + pub fn execute(&self) { + let capnp_message = self.capnp_message(); -impl HelloWorldTextProjectionRoundTripTestObject { - pub fn execute_round_trip_test(&self) { - let hello_world_text_message = self.hello_world_capnp_text_message(); - - let packed_capnp_bytes = self.encode_capnp_text_message_into_packed_capnp_bytes( - hello_world_text_message, - ); + let packed_capnp_bytes = self.encode_capnp_text_message_into_packed_capnp_bytes(capnp_message); let displayed_text = self.run_application_and_capture_stdout(packed_capnp_bytes); assert_eq!(displayed_text.trim_end(), "hello, world"); } - fn hello_world_capnp_text_message(&self) -> &'static str { - "(helloWorldUtf8Text = \"hello, world\")" + fn capnp_message(&self) -> &'static str { + "(text = \"hello, world\")" } fn encode_capnp_text_message_into_packed_capnp_bytes(&self, capnp_text_message: &str) -> Vec { @@ -29,8 +23,8 @@ impl HelloWorldTextProjectionRoundTripTestObject { capnp_encode_command .arg("encode") .arg("--packed") - .arg("--schema").arg("schema/hello_world.capnp") - .arg("HelloWorld") + .arg("--schema").arg("schema/message.capnp") + .arg("Message") .current_dir(self.types_crate_root_path()) .stdin(Stdio::piped()) .stdout(Stdio::piped()) @@ -58,7 +52,7 @@ impl HelloWorldTextProjectionRoundTripTestObject { .arg("run") .arg("-q") .arg("-p") - .arg("show_hello_world_from_stdin") + .arg("show_from_stdin") .current_dir(self.workspace_root_path()) .stdin(Stdio::piped()) .stdout(Stdio::piped()) @@ -93,7 +87,7 @@ impl HelloWorldTextProjectionRoundTripTestObject { } #[test] -fn hello_world_text_projection_round_trip() { - let test_object = HelloWorldTextProjectionRoundTripTestObject; - test_object.execute_round_trip_test(); +fn text_projection_round_trip() { + let test_object = TextProjectionRoundTripTest; + test_object.execute(); }