From 9ab70c10e158d6a9a7039f99ebd3e04fd9f70601 Mon Sep 17 00:00:00 2001 From: Tyr Chen Date: Wed, 20 Oct 2021 22:26:04 -0700 Subject: [PATCH] add code for 24 --- 24_advanced_trait_objects/Cargo.toml | 15 +++++ .../benches/trait_object.rs | 39 +++++++++++ 24_advanced_trait_objects/src/lib.rs | 5 ++ 24_advanced_trait_objects/src/service.rs | 39 +++++++++++ .../src/trait_object_in_fn.rs | 65 +++++++++++++++++++ Cargo.toml | 3 +- 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 24_advanced_trait_objects/Cargo.toml create mode 100644 24_advanced_trait_objects/benches/trait_object.rs create mode 100644 24_advanced_trait_objects/src/lib.rs create mode 100644 24_advanced_trait_objects/src/service.rs create mode 100644 24_advanced_trait_objects/src/trait_object_in_fn.rs diff --git a/24_advanced_trait_objects/Cargo.toml b/24_advanced_trait_objects/Cargo.toml new file mode 100644 index 0000000..3ee1adb --- /dev/null +++ b/24_advanced_trait_objects/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "advanced_trait_objects" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[dev-dependencies] +criterion = "0.3" + +[[bench]] +name = "trait_object" +harness = false diff --git a/24_advanced_trait_objects/benches/trait_object.rs b/24_advanced_trait_objects/benches/trait_object.rs new file mode 100644 index 0000000..e89bc02 --- /dev/null +++ b/24_advanced_trait_objects/benches/trait_object.rs @@ -0,0 +1,39 @@ +use advanced_trait_objects::{ + execute_boxed_trait_object, execute_generics, execute_trait_object, Shell, +}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +pub fn generics_benchmark(c: &mut Criterion) { + c.bench_function("generics", |b| { + b.iter(|| { + let cmd = Shell::new("ls", &[]); + execute_generics(black_box(&cmd)).unwrap(); + }) + }); +} + +pub fn trait_object_benchmark(c: &mut Criterion) { + c.bench_function("trait object", |b| { + b.iter(|| { + let cmd = Shell::new("ls", &[]); + execute_trait_object(black_box(&cmd)).unwrap(); + }) + }); +} + +pub fn boxed_object_benchmark(c: &mut Criterion) { + c.bench_function("boxed object", |b| { + b.iter(|| { + let cmd = Box::new(Shell::new("ls", &[])); + execute_boxed_trait_object(black_box(cmd)).unwrap(); + }) + }); +} + +criterion_group!( + benches, + generics_benchmark, + trait_object_benchmark, + boxed_object_benchmark +); +criterion_main!(benches); diff --git a/24_advanced_trait_objects/src/lib.rs b/24_advanced_trait_objects/src/lib.rs new file mode 100644 index 0000000..1f82532 --- /dev/null +++ b/24_advanced_trait_objects/src/lib.rs @@ -0,0 +1,5 @@ +mod service; +mod trait_object_in_fn; + +pub use service::*; +pub use trait_object_in_fn::*; diff --git a/24_advanced_trait_objects/src/service.rs b/24_advanced_trait_objects/src/service.rs new file mode 100644 index 0000000..e2d5b9d --- /dev/null +++ b/24_advanced_trait_objects/src/service.rs @@ -0,0 +1,39 @@ +use std::{error::Error, sync::Arc}; + +// 定义类型,让 KV server 里的 trait 可以被编译通过 +pub type KvError = Box; +pub struct Value(i32); +pub struct Kvpair(i32, i32); + +/// 对存储的抽象,我们不关心数据存在哪儿,但需要定义外界如何和存储打交道 +pub trait Storage: Send + Sync + 'static { + fn get(&self, table: &str, key: &str) -> Result, KvError>; + fn set(&self, table: &str, key: String, value: Value) -> Result, KvError>; + fn contains(&self, table: &str, key: &str) -> Result; + fn del(&self, table: &str, key: &str) -> Result, KvError>; + fn get_all(&self, table: &str) -> Result, KvError>; + fn get_iter(&self, table: &str) -> Result>, KvError>; +} + +// 使用 trait object,不需要泛型参数,也不需要 ServiceInner 了 +pub struct Service { + pub store: Arc, +} + +// impl 的代码略微简单一些 +impl Service { + pub fn new(store: S) -> Self { + Self { + store: Arc::new(store), + } + } +} + +// 实现 trait 时也不需要带着泛型参数 +impl Clone for Service { + fn clone(&self) -> Self { + Self { + store: Arc::clone(&self.store), + } + } +} diff --git a/24_advanced_trait_objects/src/trait_object_in_fn.rs b/24_advanced_trait_objects/src/trait_object_in_fn.rs new file mode 100644 index 0000000..757fbb6 --- /dev/null +++ b/24_advanced_trait_objects/src/trait_object_in_fn.rs @@ -0,0 +1,65 @@ +use std::{error::Error, process::Command}; + +pub type BoxedError = Box; + +pub trait Executor { + fn run(&self) -> Result, BoxedError>; +} + +pub struct Shell<'a, 'b> { + cmd: &'a str, + args: &'b [&'a str], +} + +impl<'a, 'b> Shell<'a, 'b> { + pub fn new(cmd: &'a str, args: &'b [&'a str]) -> Self { + Self { cmd, args } + } +} + +impl<'a, 'b> Executor for Shell<'a, 'b> { + fn run(&self) -> Result, BoxedError> { + let output = Command::new(self.cmd).args(self.args).output()?; + Ok(output.status.code()) + } +} + +/// 使用泛型参数 +pub fn execute_generics(cmd: &impl Executor) -> Result, BoxedError> { + cmd.run() +} + +/// 使用 trait object: &dyn T +pub fn execute_trait_object(cmd: &dyn Executor) -> Result, BoxedError> { + cmd.run() +} + +/// 使用 trait object: Box +pub fn execute_boxed_trait_object(cmd: Box) -> Result, BoxedError> { + cmd.run() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn shell_shall_work() { + let cmd = Shell::new("ls", &[]); + let result = cmd.run().unwrap(); + assert_eq!(result, Some(0)); + } + + #[test] + fn execute_shall_work() { + let cmd = Shell::new("ls", &[]); + + let result = execute_generics(&cmd).unwrap(); + assert_eq!(result, Some(0)); + let result = execute_trait_object(&cmd).unwrap(); + assert_eq!(result, Some(0)); + let boxed = Box::new(cmd); + let result = execute_boxed_trait_object(boxed).unwrap(); + assert_eq!(result, Some(0)); + } +} diff --git a/Cargo.toml b/Cargo.toml index ccae2be..12c2cdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,5 +24,6 @@ members = [ "19_closure", "21_kv", "mid_term_rgrep", - "23_advanced_generics" + "23_advanced_generics", + "24_advanced_trait_objects", ]