mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-11-09 13:39:46 -05:00
rustfmt everything
I want to make the project more accessible by not expecting folks to match my idiosyncratic style. Now almost [1] everything is written in the "standard" style. CI enforces this. [1] "Almost": I used #[rustfmt::skip] in a few sections where I felt aligning things in columns significantly improves readability.
This commit is contained in:
@@ -35,13 +35,13 @@ use libc;
|
||||
use log::warn;
|
||||
use parking_lot::Mutex;
|
||||
use std::mem;
|
||||
use std::sync::{Arc, mpsc};
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::thread;
|
||||
use std::time::Duration as StdDuration;
|
||||
use time::{Duration, Timespec};
|
||||
|
||||
/// Abstract interface to the system clocks. This is for testability.
|
||||
pub trait Clocks : Send + Sync + 'static {
|
||||
pub trait Clocks: Send + Sync + 'static {
|
||||
/// Gets the current time from `CLOCK_REALTIME`.
|
||||
fn realtime(&self) -> Timespec;
|
||||
|
||||
@@ -52,19 +52,29 @@ pub trait Clocks : Send + Sync + 'static {
|
||||
fn sleep(&self, how_long: Duration);
|
||||
|
||||
/// Calls `rcv.recv_timeout` or substitutes a test implementation.
|
||||
fn recv_timeout<T>(&self, rcv: &mpsc::Receiver<T>,
|
||||
timeout: StdDuration) -> Result<T, mpsc::RecvTimeoutError>;
|
||||
fn recv_timeout<T>(
|
||||
&self,
|
||||
rcv: &mpsc::Receiver<T>,
|
||||
timeout: StdDuration,
|
||||
) -> Result<T, mpsc::RecvTimeoutError>;
|
||||
}
|
||||
|
||||
pub fn retry_forever<C, T, E>(clocks: &C, f: &mut dyn FnMut() -> Result<T, E>) -> T
|
||||
where C: Clocks, E: Into<Error> {
|
||||
where
|
||||
C: Clocks,
|
||||
E: Into<Error>,
|
||||
{
|
||||
loop {
|
||||
let e = match f() {
|
||||
Ok(t) => return t,
|
||||
Err(e) => e.into(),
|
||||
};
|
||||
let sleep_time = Duration::seconds(1);
|
||||
warn!("sleeping for {:?} after error: {}", sleep_time, crate::error::prettify_failure(&e));
|
||||
warn!(
|
||||
"sleeping for {:?} after error: {}",
|
||||
sleep_time,
|
||||
crate::error::prettify_failure(&e)
|
||||
);
|
||||
clocks.sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
@@ -84,8 +94,12 @@ impl RealClocks {
|
||||
}
|
||||
|
||||
impl Clocks for RealClocks {
|
||||
fn realtime(&self) -> Timespec { self.get(libc::CLOCK_REALTIME) }
|
||||
fn monotonic(&self) -> Timespec { self.get(libc::CLOCK_MONOTONIC) }
|
||||
fn realtime(&self) -> Timespec {
|
||||
self.get(libc::CLOCK_REALTIME)
|
||||
}
|
||||
fn monotonic(&self) -> Timespec {
|
||||
self.get(libc::CLOCK_MONOTONIC)
|
||||
}
|
||||
|
||||
fn sleep(&self, how_long: Duration) {
|
||||
match how_long.to_std() {
|
||||
@@ -94,8 +108,11 @@ impl Clocks for RealClocks {
|
||||
};
|
||||
}
|
||||
|
||||
fn recv_timeout<T>(&self, rcv: &mpsc::Receiver<T>,
|
||||
timeout: StdDuration) -> Result<T, mpsc::RecvTimeoutError> {
|
||||
fn recv_timeout<T>(
|
||||
&self,
|
||||
rcv: &mpsc::Receiver<T>,
|
||||
timeout: StdDuration,
|
||||
) -> Result<T, mpsc::RecvTimeoutError> {
|
||||
rcv.recv_timeout(timeout)
|
||||
}
|
||||
}
|
||||
@@ -119,7 +136,11 @@ impl<'a, C: Clocks + ?Sized, S: AsRef<str>, F: FnOnce() -> S + 'a> TimerGuard<'a
|
||||
}
|
||||
|
||||
impl<'a, C, S, F> Drop for TimerGuard<'a, C, S, F>
|
||||
where C: Clocks + ?Sized, S: AsRef<str>, F: FnOnce() -> S + 'a {
|
||||
where
|
||||
C: Clocks + ?Sized,
|
||||
S: AsRef<str>,
|
||||
F: FnOnce() -> S + 'a,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
let elapsed = self.clocks.monotonic() - self.start;
|
||||
if elapsed.num_seconds() >= 1 {
|
||||
@@ -148,8 +169,12 @@ impl SimulatedClocks {
|
||||
}
|
||||
|
||||
impl Clocks for SimulatedClocks {
|
||||
fn realtime(&self) -> Timespec { self.0.boot + *self.0.uptime.lock() }
|
||||
fn monotonic(&self) -> Timespec { Timespec::new(0, 0) + *self.0.uptime.lock() }
|
||||
fn realtime(&self) -> Timespec {
|
||||
self.0.boot + *self.0.uptime.lock()
|
||||
}
|
||||
fn monotonic(&self) -> Timespec {
|
||||
Timespec::new(0, 0) + *self.0.uptime.lock()
|
||||
}
|
||||
|
||||
/// Advances the clock by the specified amount without actually sleeping.
|
||||
fn sleep(&self, how_long: Duration) {
|
||||
@@ -158,8 +183,11 @@ impl Clocks for SimulatedClocks {
|
||||
}
|
||||
|
||||
/// Advances the clock by the specified amount if data is not immediately available.
|
||||
fn recv_timeout<T>(&self, rcv: &mpsc::Receiver<T>,
|
||||
timeout: StdDuration) -> Result<T, mpsc::RecvTimeoutError> {
|
||||
fn recv_timeout<T>(
|
||||
&self,
|
||||
rcv: &mpsc::Receiver<T>,
|
||||
timeout: StdDuration,
|
||||
) -> Result<T, mpsc::RecvTimeoutError> {
|
||||
let r = rcv.recv_timeout(StdDuration::new(0, 0));
|
||||
if let Err(_) = r {
|
||||
self.sleep(Duration::from_std(timeout).unwrap());
|
||||
|
||||
@@ -38,8 +38,11 @@ pub fn prettify_failure(e: &failure::Error) -> String {
|
||||
write!(&mut msg, "\ncaused by: {}", cause).unwrap();
|
||||
}
|
||||
if e.backtrace().is_empty() {
|
||||
write!(&mut msg, "\n\n(set environment variable RUST_BACKTRACE=1 to see backtraces)")
|
||||
.unwrap();
|
||||
write!(
|
||||
&mut msg,
|
||||
"\n\n(set environment variable RUST_BACKTRACE=1 to see backtraces)"
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
write!(&mut msg, "\n\nBacktrace:\n{}", e.backtrace()).unwrap();
|
||||
}
|
||||
@@ -73,7 +76,9 @@ impl Fail for Error {
|
||||
|
||||
impl From<ErrorKind> for Error {
|
||||
fn from(kind: ErrorKind) -> Error {
|
||||
Error { inner: Context::new(kind) }
|
||||
Error {
|
||||
inner: Context::new(kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +117,8 @@ impl fmt::Display for Error {
|
||||
/// which is a nice general-purpose classification of errors. See that link for descriptions of
|
||||
/// each error.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
|
||||
#[non_exhaustive]
|
||||
#[rustfmt::skip]
|
||||
pub enum ErrorKind {
|
||||
#[fail(display = "Cancelled")] Cancelled,
|
||||
#[fail(display = "Unknown")] Unknown,
|
||||
@@ -129,7 +136,6 @@ pub enum ErrorKind {
|
||||
#[fail(display = "Internal")] Internal,
|
||||
#[fail(display = "Unavailable")] Unavailable,
|
||||
#[fail(display = "Data loss")] DataLoss,
|
||||
#[doc(hidden)] #[fail(display = "__Nonexhaustive")] __Nonexhaustive,
|
||||
}
|
||||
|
||||
/// Extension methods for `Result`.
|
||||
@@ -146,7 +152,10 @@ pub trait ResultExt<T, E> {
|
||||
fn err_kind(self, k: ErrorKind) -> Result<T, Error>;
|
||||
}
|
||||
|
||||
impl<T, E> ResultExt<T, E> for Result<T, E> where E: Into<failure::Error> {
|
||||
impl<T, E> ResultExt<T, E> for Result<T, E>
|
||||
where
|
||||
E: Into<failure::Error>,
|
||||
{
|
||||
fn err_kind(self, k: ErrorKind) -> Result<T, Error> {
|
||||
self.map_err(|e| e.into().context(k).into())
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
pub mod clock;
|
||||
pub mod time;
|
||||
mod error;
|
||||
pub mod strutil;
|
||||
pub mod time;
|
||||
|
||||
pub use crate::error::{Error, ErrorKind, ResultExt, prettify_failure};
|
||||
pub use crate::error::{prettify_failure, Error, ErrorKind, ResultExt};
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use nom::IResult;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{tag, take_while1};
|
||||
use nom::character::complete::space0;
|
||||
use nom::combinator::{map, map_res, opt};
|
||||
use nom::sequence::{delimited, tuple};
|
||||
use nom::IResult;
|
||||
use std::fmt::Write as _;
|
||||
|
||||
static MULTIPLIERS: [(char, u64); 4] = [
|
||||
@@ -48,7 +48,7 @@ static MULTIPLIERS: [(char, u64); 4] = [
|
||||
pub fn encode_size(mut raw: i64) -> String {
|
||||
let mut encoded = String::new();
|
||||
for &(c, n) in &MULTIPLIERS {
|
||||
if raw >= 1i64<<n {
|
||||
if raw >= 1i64 << n {
|
||||
write!(&mut encoded, "{}{} ", raw >> n, c).unwrap();
|
||||
raw &= (1i64 << n) - 1;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ pub fn encode_size(mut raw: i64) -> String {
|
||||
if raw > 0 || encoded.len() == 0 {
|
||||
write!(&mut encoded, "{}", raw).unwrap();
|
||||
} else {
|
||||
encoded.pop(); // remove trailing space.
|
||||
encoded.pop(); // remove trailing space.
|
||||
}
|
||||
encoded
|
||||
}
|
||||
@@ -64,24 +64,24 @@ pub fn encode_size(mut raw: i64) -> String {
|
||||
fn decode_sizepart(input: &str) -> IResult<&str, i64> {
|
||||
map(
|
||||
tuple((
|
||||
map_res(take_while1(|c: char| c.is_ascii_digit()),
|
||||
|input: &str| i64::from_str_radix(input, 10)),
|
||||
map_res(take_while1(|c: char| c.is_ascii_digit()), |input: &str| {
|
||||
i64::from_str_radix(input, 10)
|
||||
}),
|
||||
opt(alt((
|
||||
nom::combinator::value(1<<40, tag("T")),
|
||||
nom::combinator::value(1<<30, tag("G")),
|
||||
nom::combinator::value(1<<20, tag("M")),
|
||||
nom::combinator::value(1<<10, tag("K"))
|
||||
)))
|
||||
nom::combinator::value(1 << 40, tag("T")),
|
||||
nom::combinator::value(1 << 30, tag("G")),
|
||||
nom::combinator::value(1 << 20, tag("M")),
|
||||
nom::combinator::value(1 << 10, tag("K")),
|
||||
))),
|
||||
)),
|
||||
|(n, opt_unit)| n * opt_unit.unwrap_or(1)
|
||||
|(n, opt_unit)| n * opt_unit.unwrap_or(1),
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn decode_size_internal(input: &str) -> IResult<&str, i64> {
|
||||
nom::multi::fold_many1(
|
||||
delimited(space0, decode_sizepart, space0),
|
||||
0,
|
||||
|sum, i| sum + i)(input)
|
||||
nom::multi::fold_many1(delimited(space0, decode_sizepart, space0), 0, |sum, i| {
|
||||
sum + i
|
||||
})(input)
|
||||
}
|
||||
|
||||
/// Decodes a human-readable size as output by encode_size.
|
||||
@@ -95,12 +95,15 @@ pub fn decode_size(encoded: &str) -> Result<i64, ()> {
|
||||
|
||||
/// Returns a hex-encoded version of the input.
|
||||
pub fn hex(raw: &[u8]) -> String {
|
||||
const HEX_CHARS: [u8; 16] = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
|
||||
b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f'];
|
||||
#[rustfmt::skip]
|
||||
const HEX_CHARS: [u8; 16] = [
|
||||
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
|
||||
b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f',
|
||||
];
|
||||
let mut hex = Vec::with_capacity(2 * raw.len());
|
||||
for b in raw {
|
||||
hex.push(HEX_CHARS[((b & 0xf0) >> 4) as usize]);
|
||||
hex.push(HEX_CHARS[( b & 0x0f ) as usize]);
|
||||
hex.push(HEX_CHARS[(b & 0x0f) as usize]);
|
||||
}
|
||||
unsafe { String::from_utf8_unchecked(hex) }
|
||||
}
|
||||
@@ -108,8 +111,8 @@ pub fn hex(raw: &[u8]) -> String {
|
||||
/// Returns [0, 16) or error.
|
||||
fn dehex_byte(hex_byte: u8) -> Result<u8, ()> {
|
||||
match hex_byte {
|
||||
b'0' ..= b'9' => Ok(hex_byte - b'0'),
|
||||
b'a' ..= b'f' => Ok(hex_byte - b'a' + 10),
|
||||
b'0'..=b'9' => Ok(hex_byte - b'0'),
|
||||
b'a'..=b'f' => Ok(hex_byte - b'a' + 10),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@@ -122,7 +125,7 @@ pub fn dehex(hexed: &[u8]) -> Result<[u8; 20], ()> {
|
||||
}
|
||||
let mut out = [0; 20];
|
||||
for i in 0..20 {
|
||||
out[i] = (dehex_byte(hexed[i<<1])? << 4) + dehex_byte(hexed[(i<<1) + 1])?;
|
||||
out[i] = (dehex_byte(hexed[i << 1])? << 4) + dehex_byte(hexed[(i << 1) + 1])?;
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
|
||||
//! Time and durations for Moonfire NVR's internal format.
|
||||
|
||||
use failure::{Error, bail, format_err};
|
||||
use failure::{bail, format_err, Error};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{tag, take_while_m_n};
|
||||
use nom::combinator::{map, map_res, opt};
|
||||
use nom::sequence::{preceded, tuple};
|
||||
use std::ops;
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
use std::str::FromStr;
|
||||
use time;
|
||||
|
||||
@@ -50,8 +50,10 @@ pub struct Time(pub i64);
|
||||
|
||||
/// Returns a parser for a `len`-digit non-negative number which fits into an i32.
|
||||
fn fixed_len_num<'a>(len: usize) -> impl FnMut(&'a str) -> IResult<&'a str, i32> {
|
||||
map_res(take_while_m_n(len, len, |c: char| c.is_ascii_digit()),
|
||||
|input: &str| i32::from_str_radix(input, 10))
|
||||
map_res(
|
||||
take_while_m_n(len, len, |c: char| c.is_ascii_digit()),
|
||||
|input: &str| i32::from_str_radix(input, 10),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parses `YYYY-mm-dd` into pieces.
|
||||
@@ -59,7 +61,7 @@ fn parse_datepart(input: &str) -> IResult<&str, (i32, i32, i32)> {
|
||||
tuple((
|
||||
fixed_len_num(4),
|
||||
preceded(tag("-"), fixed_len_num(2)),
|
||||
preceded(tag("-"), fixed_len_num(2))
|
||||
preceded(tag("-"), fixed_len_num(2)),
|
||||
))(input)
|
||||
}
|
||||
|
||||
@@ -67,9 +69,9 @@ fn parse_datepart(input: &str) -> IResult<&str, (i32, i32, i32)> {
|
||||
fn parse_timepart(input: &str) -> IResult<&str, (i32, i32, i32, i32)> {
|
||||
let (input, (hr, _, min)) = tuple((fixed_len_num(2), tag(":"), fixed_len_num(2)))(input)?;
|
||||
let (input, stuff) = opt(tuple((
|
||||
preceded(tag(":"), fixed_len_num(2)),
|
||||
opt(preceded(tag(":"), fixed_len_num(5)))
|
||||
)))(input)?;
|
||||
preceded(tag(":"), fixed_len_num(2)),
|
||||
opt(preceded(tag(":"), fixed_len_num(5))),
|
||||
)))(input)?;
|
||||
let (sec, opt_subsec) = stuff.unwrap_or((0, None));
|
||||
Ok((input, (hr, min, sec, opt_subsec.unwrap_or(0))))
|
||||
}
|
||||
@@ -77,18 +79,23 @@ fn parse_timepart(input: &str) -> IResult<&str, (i32, i32, i32, i32)> {
|
||||
/// Parses `Z` (UTC) or `{+,-,}HH:MM` into a time zone offset in seconds.
|
||||
fn parse_zone(input: &str) -> IResult<&str, i32> {
|
||||
alt((
|
||||
nom::combinator::value(0, tag("Z")),
|
||||
map(
|
||||
tuple((
|
||||
opt(nom::character::complete::one_of(&b"+-"[..])),
|
||||
fixed_len_num(2),
|
||||
tag(":"),
|
||||
fixed_len_num(2)
|
||||
)),
|
||||
|(sign, hr, _, min)| {
|
||||
let off = hr * 3600 + min * 60;
|
||||
if sign == Some('-') { off } else { -off }
|
||||
})
|
||||
nom::combinator::value(0, tag("Z")),
|
||||
map(
|
||||
tuple((
|
||||
opt(nom::character::complete::one_of(&b"+-"[..])),
|
||||
fixed_len_num(2),
|
||||
tag(":"),
|
||||
fixed_len_num(2),
|
||||
)),
|
||||
|(sign, hr, _, min)| {
|
||||
let off = hr * 3600 + min * 60;
|
||||
if sign == Some('-') {
|
||||
off
|
||||
} else {
|
||||
-off
|
||||
}
|
||||
},
|
||||
),
|
||||
))(input)
|
||||
}
|
||||
|
||||
@@ -97,8 +104,12 @@ impl Time {
|
||||
Time(tm.sec * TIME_UNITS_PER_SEC + tm.nsec as i64 * TIME_UNITS_PER_SEC / 1_000_000_000)
|
||||
}
|
||||
|
||||
pub const fn min_value() -> Self { Time(i64::min_value()) }
|
||||
pub const fn max_value() -> Self { Time(i64::max_value()) }
|
||||
pub const fn min_value() -> Self {
|
||||
Time(i64::min_value())
|
||||
}
|
||||
pub const fn max_value() -> Self {
|
||||
Time(i64::max_value())
|
||||
}
|
||||
|
||||
/// Parses a time as either 90,000ths of a second since epoch or a RFC 3339-like string.
|
||||
///
|
||||
@@ -112,20 +123,21 @@ impl Time {
|
||||
// First try parsing as 90,000ths of a second since epoch.
|
||||
match i64::from_str(input) {
|
||||
Ok(i) => return Ok(Time(i)),
|
||||
Err(_) => {},
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
// If that failed, parse as a time string or bust.
|
||||
let (remaining, ((tm_year, tm_mon, tm_mday), opt_time, opt_zone)) =
|
||||
tuple((parse_datepart,
|
||||
opt(preceded(tag("T"), parse_timepart)),
|
||||
opt(parse_zone)))(input)
|
||||
.map_err(|e| match e {
|
||||
nom::Err::Incomplete(_) => format_err!("incomplete"),
|
||||
nom::Err::Error(e) | nom::Err::Failure(e) => {
|
||||
format_err!("{}", nom::error::convert_error(input, e))
|
||||
}
|
||||
})?;
|
||||
let (remaining, ((tm_year, tm_mon, tm_mday), opt_time, opt_zone)) = tuple((
|
||||
parse_datepart,
|
||||
opt(preceded(tag("T"), parse_timepart)),
|
||||
opt(parse_zone),
|
||||
))(input)
|
||||
.map_err(|e| match e {
|
||||
nom::Err::Incomplete(_) => format_err!("incomplete"),
|
||||
nom::Err::Error(e) | nom::Err::Failure(e) => {
|
||||
format_err!("{}", nom::error::convert_error(input, e))
|
||||
}
|
||||
})?;
|
||||
if remaining != "" {
|
||||
bail!("unexpected suffix {:?} following time string", remaining);
|
||||
}
|
||||
@@ -166,32 +178,44 @@ impl Time {
|
||||
}
|
||||
|
||||
/// Convert to unix seconds by floor method (rounding down).
|
||||
pub fn unix_seconds(&self) -> i64 { self.0 / TIME_UNITS_PER_SEC }
|
||||
pub fn unix_seconds(&self) -> i64 {
|
||||
self.0 / TIME_UNITS_PER_SEC
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for Time {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> { Self::parse(s) }
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::parse(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Time {
|
||||
type Output = Duration;
|
||||
fn sub(self, rhs: Time) -> Duration { Duration(self.0 - rhs.0) }
|
||||
fn sub(self, rhs: Time) -> Duration {
|
||||
Duration(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::AddAssign<Duration> for Time {
|
||||
fn add_assign(&mut self, rhs: Duration) { self.0 += rhs.0 }
|
||||
fn add_assign(&mut self, rhs: Duration) {
|
||||
self.0 += rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add<Duration> for Time {
|
||||
type Output = Time;
|
||||
fn add(self, rhs: Duration) -> Time { Time(self.0 + rhs.0) }
|
||||
fn add(self, rhs: Duration) -> Time {
|
||||
Time(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub<Duration> for Time {
|
||||
type Output = Time;
|
||||
fn sub(self, rhs: Duration) -> Time { Time(self.0 - rhs.0) }
|
||||
fn sub(self, rhs: Duration) -> Time {
|
||||
Time(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Time {
|
||||
@@ -203,11 +227,20 @@ impl fmt::Debug for Time {
|
||||
|
||||
impl fmt::Display for Time {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let tm = time::at(time::Timespec{sec: self.0 / TIME_UNITS_PER_SEC, nsec: 0});
|
||||
let tm = time::at(time::Timespec {
|
||||
sec: self.0 / TIME_UNITS_PER_SEC,
|
||||
nsec: 0,
|
||||
});
|
||||
let zone_minutes = tm.tm_utcoff.abs() / 60;
|
||||
write!(f, "{}:{:05}{}{:02}:{:02}", tm.strftime("%FT%T").or_else(|_| Err(fmt::Error))?,
|
||||
self.0 % TIME_UNITS_PER_SEC,
|
||||
if tm.tm_utcoff > 0 { '+' } else { '-' }, zone_minutes / 60, zone_minutes % 60)
|
||||
write!(
|
||||
f,
|
||||
"{}:{:05}{}{:02}:{:02}",
|
||||
tm.strftime("%FT%T").or_else(|_| Err(fmt::Error))?,
|
||||
self.0 % TIME_UNITS_PER_SEC,
|
||||
if tm.tm_utcoff > 0 { '+' } else { '-' },
|
||||
zone_minutes / 60,
|
||||
zone_minutes % 60
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,18 +275,33 @@ impl fmt::Display for Duration {
|
||||
false
|
||||
};
|
||||
if hours > 0 {
|
||||
write!(f, "{}{} hour{}", if have_written { " " } else { "" },
|
||||
hours, if hours == 1 { "" } else { "s" })?;
|
||||
write!(
|
||||
f,
|
||||
"{}{} hour{}",
|
||||
if have_written { " " } else { "" },
|
||||
hours,
|
||||
if hours == 1 { "" } else { "s" }
|
||||
)?;
|
||||
have_written = true;
|
||||
}
|
||||
if minutes > 0 {
|
||||
write!(f, "{}{} minute{}", if have_written { " " } else { "" },
|
||||
minutes, if minutes == 1 { "" } else { "s" })?;
|
||||
write!(
|
||||
f,
|
||||
"{}{} minute{}",
|
||||
if have_written { " " } else { "" },
|
||||
minutes,
|
||||
if minutes == 1 { "" } else { "s" }
|
||||
)?;
|
||||
have_written = true;
|
||||
}
|
||||
if seconds > 0 || !have_written {
|
||||
write!(f, "{}{} second{}", if have_written { " " } else { "" },
|
||||
seconds, if seconds == 1 { "" } else { "s" })?;
|
||||
write!(
|
||||
f,
|
||||
"{}{} second{}",
|
||||
if have_written { " " } else { "" },
|
||||
seconds,
|
||||
if seconds == 1 { "" } else { "s" }
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -261,15 +309,21 @@ impl fmt::Display for Duration {
|
||||
|
||||
impl ops::Add for Duration {
|
||||
type Output = Duration;
|
||||
fn add(self, rhs: Duration) -> Duration { Duration(self.0 + rhs.0) }
|
||||
fn add(self, rhs: Duration) -> Duration {
|
||||
Duration(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::AddAssign for Duration {
|
||||
fn add_assign(&mut self, rhs: Duration) { self.0 += rhs.0 }
|
||||
fn add_assign(&mut self, rhs: Duration) {
|
||||
self.0 += rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::SubAssign for Duration {
|
||||
fn sub_assign(&mut self, rhs: Duration) { self.0 -= rhs.0 }
|
||||
fn sub_assign(&mut self, rhs: Duration) {
|
||||
self.0 -= rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -280,17 +334,18 @@ mod tests {
|
||||
fn test_parse_time() {
|
||||
std::env::set_var("TZ", "America/Los_Angeles");
|
||||
time::tzset();
|
||||
#[rustfmt::skip]
|
||||
let tests = &[
|
||||
("2006-01-02T15:04:05-07:00", 102261550050000),
|
||||
("2006-01-02T15:04:05:00001-07:00", 102261550050001),
|
||||
("2006-01-02T15:04:05-08:00", 102261874050000),
|
||||
("2006-01-02T15:04:05", 102261874050000), // implied -08:00
|
||||
("2006-01-02T15:04", 102261873600000), // implied -08:00
|
||||
("2006-01-02T15:04:05:00001", 102261874050001), // implied -08:00
|
||||
("2006-01-02T15:04:05", 102261874050000), // implied -08:00
|
||||
("2006-01-02T15:04", 102261873600000), // implied -08:00
|
||||
("2006-01-02T15:04:05:00001", 102261874050001), // implied -08:00
|
||||
("2006-01-02T15:04:05-00:00", 102259282050000),
|
||||
("2006-01-02T15:04:05Z", 102259282050000),
|
||||
("2006-01-02-08:00", 102256992000000), // implied -08:00
|
||||
("2006-01-02", 102256992000000), // implied -08:00
|
||||
("2006-01-02-08:00", 102256992000000), // implied -08:00
|
||||
("2006-01-02", 102256992000000), // implied -08:00
|
||||
("2006-01-02Z", 102254400000000),
|
||||
("102261550050000", 102261550050000),
|
||||
];
|
||||
@@ -303,7 +358,10 @@ mod tests {
|
||||
fn test_format_time() {
|
||||
std::env::set_var("TZ", "America/Los_Angeles");
|
||||
time::tzset();
|
||||
assert_eq!("2006-01-02T15:04:05:00000-08:00", format!("{}", Time(102261874050000)));
|
||||
assert_eq!(
|
||||
"2006-01-02T15:04:05:00000-08:00",
|
||||
format!("{}", Time(102261874050000))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user