Skip to content

Instantly share code, notes, and snippets.

@apua
Last active October 12, 2021 01:18
Show Gist options
  • Save apua/1d566fb0ee30bb4f27198074f5dfa127 to your computer and use it in GitHub Desktop.
Save apua/1d566fb0ee30bb4f27198074f5dfa127 to your computer and use it in GitHub Desktop.
Convert zdict trait from static to dynamic
commit f67d8e7e8509c38b3b92bc1fa37773250c46ebe3
Author: Apua
Date: Tue Oct 12 08:21:37 2021 +0800
Convert to trait object
To make possible dict as a variable, its type has to be "trait object".
A trait object has to be object safe, causes changes of the interface:
1. No more "classmethod", all method must bound to instance.
2. No associated constants, the constants have to be out of trait;
trait cannot restrict the constant, unless property methods.
Same situation as abstract class.
3. The associated type is useless because of declaring concrete type on
the trait object.
As a result, each dict cannot have different inner structure;
without the inner structure, methods need another ident to bind to.
4. Eventually, the code looks like class based oriented abstract class,
while it has class ident, property, private members, polymorphism,
single inheritance, ... but stateless and lack of class method.
The code becomes less flexible and less performance.
diff --git a/src/dict3.rs b/src/dict3.rs
index e5ca7f4..9c17f71 100644
--- a/src/dict3.rs
+++ b/src/dict3.rs
@@ -5,23 +5,24 @@ macro_rules! register_dicts {
($($d:ident),+) => {
pub fn list_dicts() {
$(
- let info = $d::Dict::INFO;
+ let info = $d::Dict.info();
println!("{}: {}\n{}\n", info.name, info.title, info.homepage_url);
)+
}
pub fn lookup(word: &str, dict_name: &str, db_cache: &Cache, opts: &Opts) {
- match dict_name {
- $( stringify!($d) => $d::Dict::lookup(word, db_cache, opts), )+
+ let dict: Box<dyn Lookup> = match dict_name {
+ $( stringify!($d) => Box::new($d::Dict),)+
_ => unreachable!(),
};
+ dict.lookup(word, db_cache, opts);
}
};
}
register_dicts! { yahoo }
#[derive(Debug)]
struct Info {
name: &'static str,
@@ -30,17 +31,21 @@ struct Info {
}
trait Lookup {
- type Content: InnerStruct;
-
- const INFO: Info;
-
- fn get_query_url(word: &str) -> String;
+ fn get_query_url(&self, word: &str) -> String;
+
+ fn info(&self) -> Info;
- fn query(url: &str) -> Self::Content;
+ fn query(&self, url: &str) -> Content;
+ fn from_json_str(&self, serialized: &str) -> Content;
+ fn to_json_string(&self, content: &Content) -> String;
+
+ fn show(&self, content: &Content);
+
- fn lookup(word: &str, db_cache: &Cache, opts: &Opts) {
+ fn lookup(&self, word: &str, db_cache: &Cache, opts: &Opts) {
- let url = Self::get_query_url(word);
+ let url = self.get_query_url(word);
- let info = Self::INFO;
+ let info = self.info();
if opts.show_provider {
println!("\x1b[34m[{}]\x1b[0m", info.name);
@@ -50,54 +55,48 @@ trait Lookup {
}
if let Some(content_string) = db_cache.query(word, info.name) {
- Self::Content::from_json_str(content_string.as_str()).show()
+ self.show(&self.from_json_str(content_string.as_str()));
} else {
- let content = Self::query(url.as_str());
+ let content = &self.query(url.as_str());
- db_cache.save(word, info.name, content.to_json_string().as_str());
+ db_cache.save(word, info.name, self.to_json_string(content).as_str());
- content.show()
+ self.show(content);
}
}
}
+struct Content;
+
-trait InnerStruct {
- fn from_json_str(serialized: &str) -> Self;
- fn to_json_string(&self) -> String;
- fn show(&self);
-}
-
mod yahoo {
- use super::{Info, Lookup, InnerStruct};
+ use super::{Info, Lookup, Content};
pub(super) struct Dict;
+
+ const INFO: Info = Info {
+ name: "yahoo",
+ title: "Yahoo Dictionary",
+ homepage_url: "https://...",
+ };
+
impl Lookup for Dict {
- type Content = Content;
- const INFO: Info = Info {
- name: "yahoo",
- title: "Yahoo Dictionary",
- homepage_url: "https://...",
- };
- fn get_query_url(word: &str) -> String {
+ fn get_query_url(&self, word: &str) -> String {
format!("http://yahoo/{word}", word=word)
}
+ fn info(&self) -> Info {
+ INFO
+ }
- fn query(url: &str) -> Self::Content {
+ fn query(&self, url: &str) -> Content {
log::debug!("url: {}", url);
log::info!("querying ...");
Content
}
- }
-
- pub(super) struct Content;
- impl InnerStruct for Content {
- fn from_json_str(_serialized: &str) -> Self {
+ fn from_json_str(&self, _serialized: &str) -> Content {
log::info!("deserialize content string");
Content
}
- fn to_json_string(&self) -> String {
+ fn to_json_string(&self, _content: &Content) -> String {
log::info!("serialize content to string");
"serialized_self".to_string()
}
- fn show(&self) {
+ fn show(&self, _content: &Content) {
log::info!("show content");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment