diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..444c17f --- /dev/null +++ b/.clang-format @@ -0,0 +1,9 @@ +--- +BasedOnStyle: Google +IndentWidth: 4 +ColumnLimit: 100 +--- +Language: Cpp +SortIncludes: false +TabWidth: 4 +UseTab: Never diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2187697..86eb995 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -212,6 +212,21 @@ jobs: - run: cargo check --all-targets - run: cargo clippy --all-targets -- -D warnings + no-docker-image-check-only: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Install Rust + id: actions-rs + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rust-src + - run: cargo +nightly check --target x86_64-unknown-haiku -Z build-std --examples + doc: runs-on: ubuntu-latest steps: @@ -253,3 +268,21 @@ jobs: - run: if cargo build --lib --target x86_64-fortanix-unknown-sgx; then exit 1; fi # Should succeed: - run: cargo build --lib --target x86_64-fortanix-unknown-sgx --features fallback + + c: + name: Lint and format C + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Node.js runtime + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Install npm + run: npm i -f -g npm@8.16.0 + + - name: Lint and check formatting with clang-format + run: npx github:artichoke/clang-format --check diff --git a/Cargo.toml b/Cargo.toml index 1e0b8ac..8f82fd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,15 @@ core-foundation-sys = "0.8.3" winapi = { version = "0.3.9", features = ["activation", "combaseapi", "objbase", "roapi", "winerror", "winstring"] } [target.'cfg(target_arch = "wasm32")'.dependencies] -js-sys = "0.3.46" +js-sys = "0.3.50" wasm-bindgen = "0.2.70" [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3" + +[target.'cfg(target_os = "haiku")'.dependencies] +iana-time-zone-haiku = { version = "0.1.0", path = "haiku" } + +[workspace] +members = [".", "haiku"] +default-members = ["."] diff --git a/haiku/Cargo.toml b/haiku/Cargo.toml new file mode 100644 index 0000000..0340bd5 --- /dev/null +++ b/haiku/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "iana-time-zone-haiku" +description = "iana-time-zone support crate for Haiku OS" +version = "0.1.0" +authors = ["René Kijewski "] +repository = "https://github.com/strawlab/iana-time-zone" +license = "MIT OR Apache-2.0" +readme = "README.md" +edition = "2018" + +[dependencies] +cxx = "1.0.34" + +[build-dependencies] +cxx-build = "1.0.34" diff --git a/haiku/LICENSE-APACHE b/haiku/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/haiku/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/haiku/LICENSE-MIT b/haiku/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/haiku/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/haiku/README.md b/haiku/README.md new file mode 100644 index 0000000..7ad49ae --- /dev/null +++ b/haiku/README.md @@ -0,0 +1,8 @@ +# iana-time-zone-haiku + +[![Crates.io](https://img.shields.io/crates/v/iana-time-zone-haiku.svg)](https://crates.io/crates/iana-time-zone-haiku) +[![Documentation](https://docs.rs/iana-time-zone/badge.svg)](https://docs.rs/iana-time-zone/) +[![Crate License](https://img.shields.io/crates/l/iana-time-zone-haiku.svg)](https://crates.io/crates/iana-time-zone-haiku) +[![build](https://github.com/strawlab/iana-time-zone/workflows/build/badge.svg?branch=master)](https://github.com/strawlab/iana-time-zone/actions?query=branch%3Amaster) + +[iana-time-zone](https://github.com/strawlab/iana-time-zone) support crate for Haiku OS. diff --git a/haiku/build.rs b/haiku/build.rs new file mode 100644 index 0000000..bb015ba --- /dev/null +++ b/haiku/build.rs @@ -0,0 +1,11 @@ +fn main() { + cxx_build::bridge("src/lib.rs") + .file("src/implementation.cc") + .flag_if_supported("-std=c++11") + .compile("tz_haiku"); + + println!("cargo:return-if-changed=include/interface.h"); + println!("cargo:return-if-changed=src/implementation.cc"); + println!("cargo:return-if-changed=src/lib.rs"); + println!("cargo:rustc-link-lib=be"); +} diff --git a/haiku/src/implementation.cc b/haiku/src/implementation.cc new file mode 100644 index 0000000..282a423 --- /dev/null +++ b/haiku/src/implementation.cc @@ -0,0 +1,62 @@ +#include "iana-time-zone-haiku/src/interface.h" +#include "iana-time-zone-haiku/src/lib.rs.h" + +#ifdef __HAIKU__ + +#include + +#include +#include +#include +#include + +size_t ::iana_time_zone_haiku::get_tz(rust::Slice buf) { + try { + static_assert(sizeof(char) == sizeof(uint8_t), "Illegal char size"); + + if (buf.empty()) { + return 0; + } + + // `BLocaleRoster::Default()` returns a reference to a statically allocated object. + // https://github.com/haiku/haiku/blob/8f16317/src/kits/locale/LocaleRoster.cpp#L143-L147 + BLocaleRoster *locale_roster(BLocaleRoster::Default()); + if (!locale_roster) { + return 0; + } + + BTimeZone tz(NULL, NULL); + if (locale_roster->GetDefaultTimeZone(&tz) != B_OK) { + return 0; + } + + BString bname(tz.ID()); + int32_t ilength(bname.Length()); + if (ilength <= 0) { + return 0; + } + + size_t length(ilength); + if (length > buf.size()) { + return 0; + } + + // BString::String() returns a borrowed string. + // https://www.haiku-os.org/docs/api/classBString.html#ae4fe78b06c8e3310093b80305e14ba87 + const char *sname(bname.String()); + if (!sname) { + return 0; + } + + std::memcpy(buf.data(), sname, length); + return length; + } catch (...) { + return 0; + } +} + +#else + +size_t ::iana_time_zone_haiku::get_tz(rust::Slice) { return 0; } + +#endif diff --git a/haiku/src/interface.h b/haiku/src/interface.h new file mode 100644 index 0000000..5913a40 --- /dev/null +++ b/haiku/src/interface.h @@ -0,0 +1,9 @@ +#pragma once + +#include "rust/cxx.h" + +#include + +namespace iana_time_zone_haiku { +size_t get_tz(rust::Slice buf); +} diff --git a/haiku/src/lib.rs b/haiku/src/lib.rs new file mode 100644 index 0000000..e0be5cd --- /dev/null +++ b/haiku/src/lib.rs @@ -0,0 +1,29 @@ +/// # iana-time-zone-haiku +/// +/// [![Crates.io](https://img.shields.io/crates/v/iana-time-zone-haiku.svg)](https://crates.io/crates/iana-time-zone-haiku) +/// [![Documentation](https://docs.rs/iana-time-zone/badge.svg)](https://docs.rs/iana-time-zone/) +/// [![Crate License](https://img.shields.io/crates/l/iana-time-zone-haiku-haiku.svg)](https://crates.io/crates/iana-time-zone-haiku) +/// [![build](https://github.com/strawlab/iana-time-zone/workflows/build/badge.svg?branch=master)](https://github.com/strawlab/iana-time-zone/actions?query=branch%3Amaster) +/// +/// [iana-time-zone](https://github.com/strawlab/iana-time-zone) support crate for Haiku OS. + +#[cxx::bridge(namespace = "iana_time_zone_haiku")] +mod ffi { + // SAFETY: in here "unsafe" is simply part of the syntax + unsafe extern "C++" { + include!("iana-time-zone-haiku/src/interface.h"); + + fn get_tz(buf: &mut [u8]) -> usize; + } +} + +pub fn get_timezone() -> Option { + // The longest name in the IANA time zone database is 25 ASCII characters long. + let mut buf = [0u8; 32]; + let len = ffi::get_tz(&mut buf); + // The name should not be empty, or excessively long. + match buf.get(..len)? { + b"" => None, + s => Some(std::str::from_utf8(s).ok()?.to_owned()), + } +} diff --git a/src/lib.rs b/src/lib.rs index ffff3a7..df5fa9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,7 @@ path = "tz_illumos.rs" )] #[cfg_attr(target_os = "android", path = "tz_android.rs")] +#[cfg_attr(target_os = "haiku", path = "tz_haiku.rs")] mod platform; /// Error types diff --git a/src/platform.rs b/src/platform.rs index 82b7f17..5992bf3 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -5,5 +5,5 @@ pub fn get_timezone_inner() -> std::result::Result Result { + iana_time_zone_haiku::get_timezone().ok_or(crate::GetTimezoneError::OsError) +}