Skip to content

Commit

Permalink
tz: change item yielded by TimeZoneNameIter to opaque type
Browse files Browse the repository at this point in the history
This should be more friendly to future API evolution here. I previously
did the simplest thing possible and wasn't really thinking about
core-only environments.

We still don't support any tzdb in core only environments, but we
theoretically could in the future. (Although there are a number of
issues to figure out. This merely fixes one of them.)

Fixes #221
  • Loading branch information
BurntSushi committed Feb 2, 2025
1 parent 603a6ca commit e69f559
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 105 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ durations, use `Span::to_duration` and then convert the `SignedDuration` to
`Timestamp::as_jiff_duration` were renamed to `Timestamp::from_duration` and
`Timestamp::as_duration`, respectively. The old deprecated routines on the
unsigned `std::time::Duration` have been removed.
* [#221](https://github.com/BurntSushi/jiff/issues/221):
Change the type of the value yielded by the `jiff::tz::TimeZoneNameIter`
iterator from `String` to `jiff::tz::TimeZoneName`. This opaque type is more
API evolution friendly. To access the string, either use `TimeZoneName`'s
`Display` trait implementation, or its `as_str` method.


0.1.29 (2025-02-02)
Expand Down
17 changes: 8 additions & 9 deletions src/tz/db/bundled/disabled.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::tz::TimeZone;
use crate::tz::{TimeZone, TimeZoneNameIter};

#[derive(Clone)]
pub(crate) struct BundledZoneInfo;
pub(crate) struct Database;

impl BundledZoneInfo {
pub(crate) fn new() -> BundledZoneInfo {
BundledZoneInfo
impl Database {
pub(crate) fn new() -> Database {
Database
}

pub(crate) fn reset(&self) {}
Expand All @@ -14,17 +14,16 @@ impl BundledZoneInfo {
None
}

#[cfg(feature = "alloc")]
pub(crate) fn available(&self) -> alloc::vec::Vec<alloc::string::String> {
alloc::vec::Vec::new()
pub(crate) fn available<'d>(&'d self) -> TimeZoneNameIter<'d> {
TimeZoneNameIter::empty()
}

pub(crate) fn is_definitively_empty(&self) -> bool {
true
}
}

impl core::fmt::Debug for BundledZoneInfo {
impl core::fmt::Debug for Database {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Bundled(unavailable)")
}
Expand Down
16 changes: 8 additions & 8 deletions src/tz/db/bundled/enabled.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use alloc::{string::String, vec::Vec};

use crate::tz::TimeZone;
use crate::tz::{TimeZone, TimeZoneNameIter};

pub(crate) struct BundledZoneInfo;
pub(crate) struct Database;

impl BundledZoneInfo {
pub(crate) fn new() -> BundledZoneInfo {
BundledZoneInfo
impl Database {
pub(crate) fn new() -> Database {
Database
}

pub(crate) fn reset(&self) {
Expand Down Expand Up @@ -36,16 +36,16 @@ impl BundledZoneInfo {
Some(tz)
}

pub(crate) fn available(&self) -> Vec<String> {
available().into_iter().map(String::from).collect()
pub(crate) fn available<'d>(&'d self) -> TimeZoneNameIter<'d> {
TimeZoneNameIter::from_iter(available())
}

pub(crate) fn is_definitively_empty(&self) -> bool {
false
}
}

impl core::fmt::Debug for BundledZoneInfo {
impl core::fmt::Debug for Database {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Bundled(available)")
}
Expand Down
23 changes: 11 additions & 12 deletions src/tz/db/concatenated/disabled.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use crate::tz::TimeZone;
use crate::tz::{TimeZone, TimeZoneNameIter};

#[derive(Clone)]
pub(crate) struct Concatenated;
pub(crate) struct Database;

impl Concatenated {
pub(crate) fn from_env() -> Concatenated {
Concatenated
impl Database {
pub(crate) fn from_env() -> Database {
Database
}

#[cfg(feature = "std")]
pub(crate) fn from_path(
path: &std::path::Path,
) -> Result<Concatenated, crate::Error> {
) -> Result<Database, crate::Error> {
Err(crate::error::err!(
"system concatenated tzdb unavailable: \
crate feature `tzdb-concatenated` is disabled, \
Expand All @@ -20,8 +20,8 @@ impl Concatenated {
))
}

pub(crate) fn none() -> Concatenated {
Concatenated
pub(crate) fn none() -> Database {
Database
}

pub(crate) fn reset(&self) {}
Expand All @@ -30,17 +30,16 @@ impl Concatenated {
None
}

#[cfg(feature = "alloc")]
pub(crate) fn available(&self) -> alloc::vec::Vec<alloc::string::String> {
alloc::vec::Vec::new()
pub(crate) fn available<'d>(&'d self) -> TimeZoneNameIter<'d> {
TimeZoneNameIter::empty()
}

pub(crate) fn is_definitively_empty(&self) -> bool {
true
}
}

impl core::fmt::Debug for Concatenated {
impl core::fmt::Debug for Database {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Concatenated(unavailable)")
}
Expand Down
36 changes: 20 additions & 16 deletions src/tz/db/concatenated/enabled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
use crate::{
error::{err, Error},
timestamp::Timestamp,
tz::{concatenated::ConcatenatedTzif, TimeZone},
tz::{concatenated::ConcatenatedTzif, TimeZone, TimeZoneNameIter},
util::{self, array_str::ArrayStr, cache::Expiration, utf8},
};

Expand All @@ -35,22 +35,22 @@ static TZDATA_LOCATIONS: &[TzdataLocation] = &[
},
];

pub(crate) struct Concatenated {
pub(crate) struct Database {
path: Option<PathBuf>,
names: Option<Names>,
zones: RwLock<CachedZones>,
}

impl Concatenated {
pub(crate) fn from_env() -> Concatenated {
impl Database {
pub(crate) fn from_env() -> Database {
let mut attempted = vec![];
for loc in TZDATA_LOCATIONS {
let path = loc.to_path_buf();
trace!(
"opening concatenated tzdata database at {}",
path.display()
);
match Concatenated::from_path(&path) {
match Database::from_path(&path) {
Ok(db) => return db,
Err(_err) => {
trace!("failed opening {}: {_err}", path.display());
Expand All @@ -63,21 +63,21 @@ impl Concatenated {
following paths: {}",
attempted.join(", "),
);
Concatenated::none()
Database::none()
}

pub(crate) fn from_path(path: &Path) -> Result<Concatenated, Error> {
pub(crate) fn from_path(path: &Path) -> Result<Database, Error> {
let names = Some(Names::new(path)?);
let zones = RwLock::new(CachedZones::new());
Ok(Concatenated { path: Some(path.to_path_buf()), names, zones })
Ok(Database { path: Some(path.to_path_buf()), names, zones })
}

/// Creates a "dummy" zoneinfo database in which all lookups fail.
pub(crate) fn none() -> Concatenated {
pub(crate) fn none() -> Database {
let path = None;
let names = None;
let zones = RwLock::new(CachedZones::new());
Concatenated { path, names, zones }
Database { path, names, zones }
}

pub(crate) fn reset(&self) {
Expand Down Expand Up @@ -185,18 +185,22 @@ impl Concatenated {
}
}

pub(crate) fn available(&self) -> Vec<String> {
let Some(path) = self.path.as_ref() else { return vec![] };
let Some(names) = self.names.as_ref() else { return vec![] };
names.available(path)
pub(crate) fn available<'d>(&'d self) -> TimeZoneNameIter<'d> {
let Some(path) = self.path.as_ref() else {
return TimeZoneNameIter::empty();
};
let Some(names) = self.names.as_ref() else {
return TimeZoneNameIter::empty();
};
TimeZoneNameIter::from_iter(names.available(path).into_iter())
}

pub(crate) fn is_definitively_empty(&self) -> bool {
self.names.is_none()
}
}

impl core::fmt::Debug for Concatenated {
impl core::fmt::Debug for Database {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Concatenated(")?;
if let Some(ref path) = self.path {
Expand Down Expand Up @@ -561,7 +565,7 @@ mod tests {
const ENV: &str = "JIFF_DEBUG_CONCATENATED_TZDATA";
let Some(val) = std::env::var_os(ENV) else { return Ok(()) };
let path = PathBuf::from(val);
let db = Concatenated::from_path(&path)?;
let db = Database::from_path(&path)?;
for name in db.available() {
std::eprintln!("{name}");
}
Expand Down
Loading

0 comments on commit e69f559

Please # to comment.