Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update docs #10

Merged
merged 1 commit into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
edition = "2021"
name = "tzf-rs"
version = "0.1.1"
version = "0.1.2"
license-file = "LICENSE"
description = "a fast timezone for Rust"
homepage = "http://github.com/ringsaturn/tzf-rs"
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# WIP: tzf's Rust port. [![Rust](https://github.com/ringsaturn/tzf-rs/actions/workflows/rust.yml/badge.svg)](https://github.com/ringsaturn/tzf-rs/actions/workflows/rust.yml)
# WIP: tzf's Rust port. [![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)

## Usage

Add to `Cargo.toml`

```toml
tzf-rs = "0.1.1"
tzf-rs = "0.1.2"
```

```rust
Expand All @@ -14,13 +14,14 @@ use tzf_rs::DefaultFinder;
fn main() {
let finder = DefaultFinder::new();

print!("{:?}\n", DefaultFinder.get_tz_name(116.3883, 39.9289));
print!("{:?}\n", finder.get_tz_name(116.3883, 39.9289));
}
```

## References:

- Documents: <https://docs.rs/tzf-rs>
- Original Go repo: <https://github.com/ringsaturn/tzf>
- Binary timezone data: <https://github.com/ringsaturn/tzf-rel>
- Geometry: <https://github.com/ringsaturn/geometry-rs>
- Geometry: use <https://github.com/ringsaturn/geometry-rs>
which is <https://github.com/tidwall/geometry>'s Rust port.
13 changes: 0 additions & 13 deletions examples/defaut.rs

This file was deleted.

13 changes: 0 additions & 13 deletions examples/finder.rs

This file was deleted.

13 changes: 0 additions & 13 deletions examples/fuzzy.rs

This file was deleted.

97 changes: 93 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
//! Fast timezone finder for Rust.
//!
//! It's designed for high performance geo queries related services like
//! weather forecast API. And most queries could return in very limited time,
//! averagely like 2000 nanoseconds.
//!
//! Please note that this package use a simplified shape data so not so accurate
//! around border.
//!
//! There are there finders implements:
//! - [Finder]: works anywhere.
//! - [FuzzyFinder]: blazing fast for most places on earth, use a preindex data.
//! Not work for places around borders.
//! - [DefaultFinder]: combine both, if [FuzzyFinder] got no data, then use [Finder].
//!
//! Preprocessed timezone data is distributed via [tzf-rel].
//!
//! It's Rust port of [tzf] and also the foundation of
//! [tzfpy] since `v0.11.0`....
//!
//! [tzf]: https://github.com/ringsaturn/tzf
//! [tzf-rel]: https://github.com/ringsaturn/tzf-rel
//! [tzfpy]: https://github.com/ringsaturn/tzfpy
//
use geometry_rs::{Point, Polygon};
use std::collections::HashMap;
use std::f64::consts::PI;
Expand All @@ -12,7 +36,7 @@ struct Item {
}

impl Item {
pub fn contain_point(&self, p: &Point) -> bool {
fn contain_point(&self, p: &Point) -> bool {
for poly in self.polys.iter() {
if poly.contains_point(*p) {
return true;
Expand All @@ -22,12 +46,20 @@ impl Item {
}
}

/// Finder use a fine tuned Ray casting algorithm implement [geometry-rs]
/// which is Rust port of [geometry] by [Josh Baker].
///
/// [geometry-rs]: https://github.com/ringsaturn/geometry-rs
/// [geometry]: https://github.com/tidwall/geometry
/// [Josh Baker]: https://github.com/tidwall
#[derive(Debug)]
pub struct Finder {
all: Vec<Item>,
}

impl Finder {
/// `from_pb` is used when you can customed timezone data, as long as
/// it's compatible with Proto's desc.
pub fn from_pb(tzs: gen::Timezones) -> Finder {
let mut f: Finder = Finder { all: vec![] };
for tz in tzs.timezones.iter() {
Expand Down Expand Up @@ -69,14 +101,30 @@ impl Finder {
return f;
}

/// new is for most general usacase.
///
/// Example:
///
/// ```rust
/// use tzf_rs::Finder;
///
/// let finder = Finder::new();
/// ```
pub fn new() -> Finder {
// let file_bytes = include_bytes!("data/combined-with-oceans.reduce.pb").to_vec();
let file_bytes: Vec<u8> = load_reduced();
let finder: Finder = Finder::from_pb(gen::Timezones::try_from(file_bytes).unwrap());
return finder;
}

// https://users.rust-lang.org/t/cannot-move-out-of-x-which-is-behind-a-shared-reference/33263
/// Example:
///
/// ```rust
/// use tzf_rs::Finder;
///
/// let finder = Finder::new();
/// assert_eq!("Asia/Shanghai", finder.get_tz_name(116.3883, 39.9289));
/// ```
pub fn get_tz_name(&self, lng: f64, lat: f64) -> &str {
// let p = &Point::new(lng, lat);
let p = geometry_rs::Point { x: lng, y: lat };
Expand All @@ -89,7 +137,18 @@ impl Finder {
}
}

// https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
/// deg2num is used to convert longitude, latitude to [Slippy map tilenames]
/// under specific zoom level.
///
/// [Slippy map tilenames]: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
///
/// Example:
///
/// ```rust
/// use tzf_rs::deg2num;
/// let ret = deg2num(116.3883, 39.9289, 7);
/// assert_eq!((105, 48), ret);
/// ```
pub fn deg2num(lng: f64, lat: f64, zoom: i64) -> (i64, i64) {
let lat_rad = lat.to_radians();
let n = f64::powf(2.0, zoom as f64);
Expand All @@ -98,6 +157,14 @@ pub fn deg2num(lng: f64, lat: f64, zoom: i64) -> (i64, i64) {
return (xtile as i64, ytile as i64);
}

/// FuzzyFinder store all preindex's tiles data in a HashMap,
/// It iterate all zoom levels for input's longitude and latitude to build
/// map key to to check if in map.
///
/// It's is very fast and use about 400ns to check if has preindex.
/// It work for most places on earch and here is a quick loop of preindex data:
/// ![](https://user-images.githubusercontent.com/13536789/200174943-7d40661e-bda5-4b79-a867-ec637e245a49.png)
///
#[derive(Debug)]
pub struct FuzzyFinder {
min_zoom: i64,
Expand All @@ -120,14 +187,26 @@ impl FuzzyFinder {
}
return f;
}

/// ```rust
/// use tzf_rs::FuzzyFinder;
///
/// let finder = FuzzyFinder::new();
/// ```
pub fn new() -> FuzzyFinder {
let file_bytes: Vec<u8> = load_preindex();
let finder: FuzzyFinder =
FuzzyFinder::from_pb(gen::PreindexTimezones::try_from(file_bytes).unwrap());
return finder;
}

/// Example:
///
/// ```rust
/// use tzf_rs::FuzzyFinder;
///
/// let finder = FuzzyFinder::new();
/// assert_eq!("Asia/Shanghai", finder.get_tz_name(116.3883, 39.9289));
/// ```
pub fn get_tz_name(&self, lng: f64, lat: f64) -> &str {
for zoom in self.min_zoom..self.max_zoom {
let idx = deg2num(lng, lat, zoom);
Expand All @@ -142,12 +221,17 @@ impl FuzzyFinder {
}
}

/// It's most recommend to use, combine both [Finder] and [FuzzyFinder].
pub struct DefaultFinder {
finder: Finder,
fuzzy_finder: FuzzyFinder,
}

impl DefaultFinder {
/// ```rust
/// use tzf_rs::DefaultFinder;
/// let finder = DefaultFinder::new();
/// ```
pub fn new() -> DefaultFinder {
let finder = Finder::new();
let fuzzy_finder = FuzzyFinder::new();
Expand All @@ -158,6 +242,11 @@ impl DefaultFinder {
return df;
}

/// ```rust
/// use tzf_rs::DefaultFinder;
/// let finder = DefaultFinder::new();
/// assert_eq!("Asia/Shanghai", finder.get_tz_name(116.3883, 39.9289));
/// ```
pub fn get_tz_name(&self, lng: f64, lat: f64) -> &str {
let fuzzy_name = self.fuzzy_finder.get_tz_name(lng, lat);
if fuzzy_name != "" {
Expand Down