From 7fa8c5e54b3fe446ff0c5021065f1acee9b942ed Mon Sep 17 00:00:00 2001 From: Even Solberg Date: Fri, 18 Aug 2023 09:51:15 -0700 Subject: [PATCH] Add back `new()` functions, README update --- README.md | 35 +++++++---------- src/bin/tzf.rs | 2 +- src/lib.rs | 92 +++++++++++++++++++++++++++++++++++++++------ tests/basic_test.rs | 2 +- tests/default.rs | 2 +- tests/fuzzy_test.rs | 2 +- 6 files changed, 98 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index cc5a409..3b84b9c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ # tzf-rs: a fast timezone finder for Rust. [![Rust](https://github.com/ringsaturn/tzf-rs/actions/workflows/rust.yml/badge.svg)](https://github.com/ringsaturn/tzf-rs/actions/workflows/rust.yml) [![Documentation](https://docs.rs/tzf-rs/badge.svg)](https://docs.rs/tzf-rs) -![](https://github.com/ringsaturn/tzf/blob/gh-pages/docs/tzf-social-media.png?raw=true) +![Time zone map of the world](https://github.com/ringsaturn/tzf/blob/gh-pages/docs/tzf-social-media.png?raw=true) -**NOTE**: this package use a simplified shape data so not so accurate around -border. +**NOTE**: This package uses simplified shape data so it is not entirely accurate around the border. ## Build options -By default, the binary is built as well. If you don't want/need it, then build -like this: +By default, the binary is built as well. If you don't want/need it, you can omit the default features and build like this: ```bash cargo build --no-default-features @@ -20,10 +18,10 @@ Or add in the below way: cargo add tzf-rs --no-default-features ``` -## Best practice +## Best Practices -It's expensive to init tzf-rs's Finder/FuzzyFinder/DefaultFinder, please -consider reuse it or as a global var. Below is a global var example: +It's expensive to init tzf-rs's `Finder`/`FuzzyFinder`/`DefaultFinder`, so please +consider reusing instances or creating one as a global variable. Below is a global variable example: ```rust use lazy_static::lazy_static; @@ -39,33 +37,28 @@ fn main() { } ``` -For reuse it, -[`racemap/rust-tz-service`](https://github.com/racemap/rust-tz-service) is a -good example. +For reuse, [`racemap/rust-tz-service`](https://github.com/racemap/rust-tz-service) provides a good example. -A Redis protocol demo could be used here: -[`ringsaturn/redizone`](https://github.com/ringsaturn/redizone). +A Redis protocol demo could be used here: [`ringsaturn/redizone`](https://github.com/ringsaturn/redizone). ## Performance -The tzf-rs package is intended for high-performance geo spatial query services, +The tzf-rs package is intended for high-performance geospatial query services, such as weather forecasting APIs. Most queries can be returned within a very -short time, averaging around 3000 nanoseconds(there is 1000ns slower compared -with Go repo `tzf` and I will continue to improve that, you can track progress +short time, averaging around 3,000 nanoseconds (about 1,000ns slower than +with Go repo `tzf`. I will continue improving this - you can track progress [here](https://github.com/ringsaturn/geometry-rs/issues/3)). Here is what has been done to improve performance: -1. Using pre-indexing to handle most queries takes approximately 1000 - nanoseconds. +1. Using pre-indexing to handle most queries takes approximately 1000 nanoseconds. 2. Using a finely-tuned Ray Casting algorithm package [`ringsaturn/geometry-rs`](https://github.com/ringsaturn/geometry-rs) to verify whether a polygon contains a point. That's all. There are no black magic tricks inside the tzf-rs. -Below is a benchmark run on global cities(about 14K), and avg time is about 3000 -ns per query: +Below is a benchmark run on global cities(about 14K), and avg time is about 3,000 ns per query: ```txt test benches_default::bench_default_finder_random_city ... bench: 2,870 ns/iter (+/- 182) @@ -81,7 +74,7 @@ You can view more details from latest benchmark from ## References -I have written an article about the history of tzf, its Rust port, and its Rust +I have written an article about the history of `tzf`, its Rust port, and its Rust port's Python binding; you can view it [here](https://blog.ringsaturn.me/en/posts/2023-01-31-history-of-tzf/). diff --git a/src/bin/tzf.rs b/src/bin/tzf.rs index a7d5aaa..e1fcd61 100644 --- a/src/bin/tzf.rs +++ b/src/bin/tzf.rs @@ -17,7 +17,7 @@ struct Cli { pub fn main() { let cli = Cli::parse(); - let finder = DefaultFinder::default(); + let finder = DefaultFinder::new(); let tz_name = finder.get_tz_name(cli.lng, cli.lat); println!("{tz_name:?}"); } diff --git a/src/lib.rs b/src/lib.rs index 6b28128..20b4ed0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ struct Item { } impl Item { - fn contain_point(&self, p: &Point) -> bool { + fn contains_point(&self, p: &Point) -> bool { for poly in &self.polys { if poly.contains_point(*p) { return true; @@ -39,6 +39,14 @@ pub struct Finder { impl Finder { /// `from_pb` is used when you can use your own timezone data, as long as /// it's compatible with Proto's desc. + /// + /// # Arguments + /// + /// * `tzs` - Timezones data. + /// + /// # Returns + /// + /// * `Finder` - A Finder instance. #[must_use] pub fn from_pb(tzs: gen::Timezones) -> Self { let mut f = Self { @@ -97,7 +105,7 @@ impl Finder { // let p = &Point::new(lng, lat); let p = geometry_rs::Point { x: lng, y: lat }; for item in &self.all { - if item.contain_point(&p) { + if item.contains_point(&p) { return &item.name; } } @@ -114,7 +122,7 @@ impl Finder { let mut ret: Vec<&str> = vec![]; let p = geometry_rs::Point { x: lng, y: lat }; for item in &self.all { - if item.contain_point(&p) { + if item.contains_point(&p) { ret.push(&item.name); } } @@ -150,9 +158,23 @@ impl Finder { pub fn data_version(&self) -> &str { &self.data_version } + + /// Creates a new, empty `Finder`. + /// + /// Example: + /// + /// ```rust + /// use tzf_rs::Finder; + /// + /// let finder = Finder::new(); + /// ``` + #[must_use] + pub fn new() -> Self { + Self::default() + } } -/// new is for most general use case. +/// Creates a new, empty `Finder`. /// /// Example: /// @@ -214,6 +236,20 @@ pub struct FuzzyFinder { data_version: String, } +impl Default for FuzzyFinder { + /// Creates a new, empty `FuzzyFinder`. + /// + /// ```rust + /// use tzf_rs::FuzzyFinder; + /// + /// let finder = FuzzyFinder::default(); + /// ``` + fn default() -> Self { + let file_bytes: Vec = load_preindex(); + Self::from_pb(gen::PreindexTimezones::try_from(file_bytes).unwrap_or_default()) + } +} + impl FuzzyFinder { #[must_use] pub fn from_pb(tzs: gen::PreindexTimezones) -> Self { @@ -232,7 +268,14 @@ impl FuzzyFinder { f } - /// Example: + /// Retrieves the time zone name for the given longitude and latitude. + /// + /// # Arguments + /// + /// * `lng` - Longitude + /// * `lat` - Latitude + /// + /// # Example: /// /// ```rust /// use tzf_rs::FuzzyFinder; @@ -260,7 +303,13 @@ impl FuzzyFinder { "" } - /// Example: + /// Gets the version of the data used by this `FuzzyFinder`. + /// + /// # Returns + /// + /// The version of the data used by this `FuzzyFinder` as a `&str`. + /// + /// # Example: /// /// ```rust /// use tzf_rs::FuzzyFinder; @@ -272,17 +321,17 @@ impl FuzzyFinder { pub fn data_version(&self) -> &str { &self.data_version } -} -impl Default for FuzzyFinder { + /// Creates a new, empty `FuzzyFinder`. + /// /// ```rust /// use tzf_rs::FuzzyFinder; /// - /// let finder = FuzzyFinder::new(); + /// let finder = FuzzyFinder::default(); /// ``` - fn default() -> Self { - let file_bytes: Vec = load_preindex(); - Self::from_pb(gen::PreindexTimezones::try_from(file_bytes).unwrap_or_default()) + #[must_use] + pub fn new() -> Self { + Self::default() } } @@ -294,6 +343,10 @@ pub struct DefaultFinder { } impl Default for DefaultFinder { + /// Creates a new, empty `DefaultFinder`. + /// + /// # Example + /// /// ```rust /// use tzf_rs::DefaultFinder; /// let finder = DefaultFinder::new(); @@ -334,6 +387,8 @@ impl DefaultFinder { self.finder.get_tz_names(lng, lat) } + /// Returns all time zone names as a `Vec<&str>`. + /// /// ```rust /// use tzf_rs::DefaultFinder; /// let finder = DefaultFinder::new(); @@ -344,6 +399,8 @@ impl DefaultFinder { self.finder.timezonenames() } + /// Returns the version of the data used by this `DefaultFinder` as a `&str`. + /// /// Example: /// /// ```rust @@ -356,4 +413,15 @@ impl DefaultFinder { pub fn data_version(&self) -> &str { &self.finder.data_version } + + /// Creates a new instance of `DefaultFinder`. + /// + /// ```rust + /// use tzf_rs::DefaultFinder; + /// let finder = DefaultFinder::new(); + /// ``` + #[must_use] + pub fn new() -> Self { + Self::default() + } } diff --git a/tests/basic_test.rs b/tests/basic_test.rs index 7259d7e..d73adb4 100644 --- a/tests/basic_test.rs +++ b/tests/basic_test.rs @@ -6,7 +6,7 @@ mod tests { #[test] fn smoke_test() { - let finder = Finder::default(); + let finder = Finder::new(); assert_eq!(finder.get_tz_name(116.3883, 39.9289), "Asia/Shanghai"); assert_eq!(finder.get_tz_name(121.3547, 31.1139), "Asia/Shanghai"); diff --git a/tests/default.rs b/tests/default.rs index 142b595..3a04ed5 100644 --- a/tests/default.rs +++ b/tests/default.rs @@ -6,7 +6,7 @@ mod tests { #[test] fn smoke_test() { - let finder = DefaultFinder::default(); + let finder = DefaultFinder::new(); assert_eq!(finder.get_tz_name(116.3883, 39.9289), "Asia/Shanghai"); assert_eq!(finder.get_tz_name(121.3547, 31.1139), "Asia/Shanghai"); diff --git a/tests/fuzzy_test.rs b/tests/fuzzy_test.rs index c6d509f..f57f360 100644 --- a/tests/fuzzy_test.rs +++ b/tests/fuzzy_test.rs @@ -14,7 +14,7 @@ mod tests { #[test] fn smoke_test() { - let finder = FuzzyFinder::default(); + let finder = FuzzyFinder::new(); assert_eq!(finder.get_tz_name(116.3883, 39.9289), "Asia/Shanghai"); assert_eq!(finder.get_tz_name(121.3547, 31.1139), "Asia/Shanghai");