Skip to content

Commit

Permalink
Add back new() functions, README update
Browse files Browse the repository at this point in the history
  • Loading branch information
evensolberg committed Aug 18, 2023
1 parent a173a80 commit 7fa8c5e
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 37 deletions.
35 changes: 14 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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/).

Expand Down
2 changes: 1 addition & 1 deletion src/bin/tzf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}");
}
92 changes: 80 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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:
///
Expand Down Expand Up @@ -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<u8> = 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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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<u8> = load_preindex();
Self::from_pb(gen::PreindexTimezones::try_from(file_bytes).unwrap_or_default())
#[must_use]
pub fn new() -> Self {
Self::default()
}
}

Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand All @@ -344,6 +399,8 @@ impl DefaultFinder {
self.finder.timezonenames()
}

/// Returns the version of the data used by this `DefaultFinder` as a `&str`.
///
/// Example:
///
/// ```rust
Expand All @@ -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()
}
}
2 changes: 1 addition & 1 deletion tests/basic_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion tests/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion tests/fuzzy_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down

0 comments on commit 7fa8c5e

Please sign in to comment.