From 474387f617737c9c03ea008733de68b917ab2d31 Mon Sep 17 00:00:00 2001 From: Etherian Date: Sat, 24 Aug 2019 00:02:05 -0400 Subject: [PATCH 01/16] feat(std): add std::time bindings --- src/lib.rs | 1 + src/std_lib.rs | 1 + src/std_lib/time.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 src/std_lib/time.rs diff --git a/src/lib.rs b/src/lib.rs index 01d0ee5b74..dfeeeb40a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -816,6 +816,7 @@ impl VmBuilder { add_extern_module(&vm, "std.io.prim", crate::std_lib::io::load); add_extern_module(&vm, "std.process.prim", crate::std_lib::process::load); add_extern_module(&vm, "std.env.prim", crate::std_lib::env::load); + add_extern_module(&vm, "std.time.prim", crate::std_lib::time::load); add_extern_module_if!( #[cfg(feature = "serialization")], diff --git a/src/std_lib.rs b/src/std_lib.rs index b7a332d453..13c6ab4421 100644 --- a/src/std_lib.rs +++ b/src/std_lib.rs @@ -7,3 +7,4 @@ pub mod process; pub mod random; #[cfg(feature = "regex")] pub mod regex; +pub mod time; diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs new file mode 100644 index 0000000000..2cf790a010 --- /dev/null +++ b/src/std_lib/time.rs @@ -0,0 +1,111 @@ +//! Module containing bindings to rust's `std::time` module. +//! +use crate::real_std::{ + time, + convert::TryInto, +}; + +use crate::vm::{ + self, + api::{Eff, IO}, + thread::Thread, + types::VmInt, + ExternModule, +}; + +#[derive(Clone, Debug, Userdata, Trace, VmType)] +#[gluon(vm_type = "std.time.types.Duration")] +#[gluon(crate_name = "::vm")] +#[gluon_trace(skip)] +struct Duration(time::Duration); + +fn as_secs(dur: &Duration) -> VmInt { + dur.0.as_secs().try_into().expect("Overflow when trying to convert Duration into seconds") +} + +fn subsec_nanos(dur: &Duration) -> VmInt { + dur.0.subsec_nanos() as VmInt +} + +#[derive(Clone, Debug, Userdata, Trace, VmType)] +#[gluon(vm_type = "std.time.types.Instant")] +#[gluon(crate_name = "::vm")] +#[gluon_trace(skip)] +struct Instant(time::Instant); + +fn instant_now(_: ()) -> IO { + IO::Value(Instant(time::Instant::now())) +} + +/// Returns `Some(later - earlier)` if `later` is the same as or later than `earlier`. +/// Returns None otherwise. +fn instant_since(later: &Instant, earlier: &Instant) -> Option { + // Note: replace with checked_duration_since when 1.38 is stable + if later.0 >= earlier.0 { + // should never panic + Some(Duration(later.0.duration_since(earlier.0))) + } else { + None + } +} + +fn instant_elapsed(earlier: &Instant) -> Duration { + Duration(earlier.0.elapsed()) +} + +#[derive(Clone, Debug, Userdata, Trace, VmType)] +#[gluon(vm_type = "std.time.types.SystemTime")] +#[gluon(crate_name = "::vm")] +#[gluon_trace(skip)] +struct SystemTime(time::SystemTime); + +fn system_time_now(_: ()) -> IO { + IO::Value(SystemTime(time::SystemTime::now())) +} + +/// Returns `Ok(later - earlier)` if `later` is the same as or later than `earlier`. +/// Returns `Err(earlier - later)` if `later` is earlier than `earlier`. +fn system_time_since(later : &SystemTime, earlier : &SystemTime) -> Result { + later.0.duration_since(earlier.0) + .map(|x| Duration(x)) + .map_err(|e| Duration(e.duration())) +} + +fn system_time_elapsed(earlier: &SystemTime) -> Result { + earlier.0.elapsed() + .map(|x| Duration(x)) + .map_err(|e| Duration(e.duration())) +} + +mod std { + pub mod time { + pub use crate::std_lib::time as prim; + } +} + +pub fn load(vm: &Thread) -> vm::Result { + vm.register_type::("std.time.types.Duration", &[])?; + vm.register_type::("std.time.types.Instant", &[])?; + vm.register_type::("std.time.types.SystemTime", &[])?; + + ExternModule::new( + vm, + record! { + type std::time::Duration => Duration, + type std::time::Instant => Instant, + type std::time::SystemTime => SystemTime, + + unix_epoch => SystemTime(time::UNIX_EPOCH), + + as_secs => primitive!(1, std::time::prim::as_secs), + subsec_nanos => primitive!(1, std::time::prim::subsec_nanos), + instant_now => primitive!(1, std::time::prim::instant_now), + instant_since => primitive!(2, std::time::prim::instant_since), + instant_elapsed => primitive!(1, std::time::prim::instant_elapsed), + system_time_now => primitive!(1, std::time::prim::system_time_now), + system_time_since => primitive!(2, std::time::prim::system_time_since), + system_time_elapsed => primitive!(1, std::time::prim::system_time_elapsed), + + }, + ) +} From 5c517091c9a6c3e22342f8bde95a411406b8d877 Mon Sep 17 00:00:00 2001 From: Etherian Date: Sat, 24 Aug 2019 00:02:37 -0400 Subject: [PATCH 02/16] feat(std): add std.time module --- std/time.glu | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 std/time.glu diff --git a/std/time.glu b/std/time.glu new file mode 100644 index 0000000000..e1b7bfc352 --- /dev/null +++ b/std/time.glu @@ -0,0 +1,8 @@ +//! Time-related functionality + +let time = import! std.time.prim + +{ + .. + time +} From a878f7b84fc4c74e91186f46120e0585ff94c29e Mon Sep 17 00:00:00 2001 From: Etherian Date: Fri, 30 Aug 2019 13:28:18 -0400 Subject: [PATCH 03/16] feat(std): restructure std.time --- src/std_lib/time.rs | 165 +++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 70 deletions(-) diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs index 2cf790a010..6d7a261db2 100644 --- a/src/std_lib/time.rs +++ b/src/std_lib/time.rs @@ -1,5 +1,5 @@ //! Module containing bindings to rust's `std::time` module. -//! + use crate::real_std::{ time, convert::TryInto, @@ -7,74 +7,92 @@ use crate::real_std::{ use crate::vm::{ self, - api::{Eff, IO}, + api::{RuntimeResult, IO}, thread::Thread, types::VmInt, ExternModule, }; -#[derive(Clone, Debug, Userdata, Trace, VmType)] -#[gluon(vm_type = "std.time.types.Duration")] -#[gluon(crate_name = "::vm")] -#[gluon_trace(skip)] -struct Duration(time::Duration); +mod duration { + use super::*; + + #[derive(Clone, Debug, Userdata, Trace, VmType)] + #[gluon_userdata(clone)] + #[gluon(vm_type = "std.time.types.Duration")] + #[gluon(crate_name = "::vm")] + #[gluon_trace(skip)] + pub(crate) struct Duration(pub(crate) time::Duration); + + pub(crate) fn as_secs(dur: &Duration) -> RuntimeResult { + dur.0.as_secs() + .try_into() + .map_err(|_| String::from("Overflow when trying to convert Duration into seconds")) + .into() + } -fn as_secs(dur: &Duration) -> VmInt { - dur.0.as_secs().try_into().expect("Overflow when trying to convert Duration into seconds") + pub(crate) fn subsec_nanos(dur: &Duration) -> VmInt { + dur.0.subsec_nanos() as VmInt + } } -fn subsec_nanos(dur: &Duration) -> VmInt { - dur.0.subsec_nanos() as VmInt -} +mod instant { + use super::{ *, duration::Duration }; -#[derive(Clone, Debug, Userdata, Trace, VmType)] -#[gluon(vm_type = "std.time.types.Instant")] -#[gluon(crate_name = "::vm")] -#[gluon_trace(skip)] -struct Instant(time::Instant); + #[derive(Clone, Debug, Userdata, Trace, VmType)] + #[gluon_userdata(clone)] + #[gluon(vm_type = "std.time.types.Instant")] + #[gluon(crate_name = "::vm")] + #[gluon_trace(skip)] + pub(crate) struct Instant(pub(crate) time::Instant); -fn instant_now(_: ()) -> IO { - IO::Value(Instant(time::Instant::now())) -} + pub(crate) fn now(_: ()) -> IO { + IO::Value(Instant(time::Instant::now())) + } -/// Returns `Some(later - earlier)` if `later` is the same as or later than `earlier`. -/// Returns None otherwise. -fn instant_since(later: &Instant, earlier: &Instant) -> Option { - // Note: replace with checked_duration_since when 1.38 is stable - if later.0 >= earlier.0 { - // should never panic - Some(Duration(later.0.duration_since(earlier.0))) - } else { - None + /// Returns `Some(later - earlier)` if `later` is the same as or later than `earlier`. + /// Returns None otherwise. + pub(crate) fn duration_since(later: &Instant, earlier: &Instant) -> Option { + // Note: replace with checked_duration_since when 1.38 is stable + if later.0 >= earlier.0 { + // should never panic + Some(Duration(later.0.duration_since(earlier.0))) + } else { + None + } } -} -fn instant_elapsed(earlier: &Instant) -> Duration { - Duration(earlier.0.elapsed()) + pub(crate) fn elapsed(earlier: &Instant) -> Duration { + Duration(earlier.0.elapsed()) + } } -#[derive(Clone, Debug, Userdata, Trace, VmType)] -#[gluon(vm_type = "std.time.types.SystemTime")] -#[gluon(crate_name = "::vm")] -#[gluon_trace(skip)] -struct SystemTime(time::SystemTime); +mod system_time { + use super::{ *, duration::Duration }; -fn system_time_now(_: ()) -> IO { - IO::Value(SystemTime(time::SystemTime::now())) -} + #[derive(Clone, Debug, Userdata, Trace, VmType)] + #[gluon_userdata(clone)] + #[gluon(vm_type = "std.time.types.SystemTime")] + #[gluon(crate_name = "::vm")] + #[gluon_trace(skip)] + pub(crate) struct SystemTime(pub(crate) time::SystemTime); -/// Returns `Ok(later - earlier)` if `later` is the same as or later than `earlier`. -/// Returns `Err(earlier - later)` if `later` is earlier than `earlier`. -fn system_time_since(later : &SystemTime, earlier : &SystemTime) -> Result { - later.0.duration_since(earlier.0) - .map(|x| Duration(x)) - .map_err(|e| Duration(e.duration())) -} + pub(crate) fn now(_: ()) -> IO { + IO::Value(SystemTime(time::SystemTime::now())) + } -fn system_time_elapsed(earlier: &SystemTime) -> Result { - earlier.0.elapsed() - .map(|x| Duration(x)) - .map_err(|e| Duration(e.duration())) + /// Returns `Ok(later - earlier)` if `later` is the same as or later than `earlier`. + /// Returns `Err(earlier - later)` if `later` is earlier than `earlier`. + pub(crate) fn duration_since(later : &SystemTime, earlier : &SystemTime) -> Result { + later.0.duration_since(earlier.0) + .map(|x| Duration(x)) + .map_err(|e| Duration(e.duration())) + } + + pub(crate) fn elapsed(earlier: &SystemTime) -> Result { + earlier.0.elapsed() + .map(|x| Duration(x)) + .map_err(|e| Duration(e.duration())) + } } mod std { @@ -84,28 +102,35 @@ mod std { } pub fn load(vm: &Thread) -> vm::Result { - vm.register_type::("std.time.types.Duration", &[])?; - vm.register_type::("std.time.types.Instant", &[])?; - vm.register_type::("std.time.types.SystemTime", &[])?; + vm.register_type::("std.time.types.Duration", &[])?; + vm.register_type::("std.time.types.Instant", &[])?; + vm.register_type::("std.time.types.SystemTime", &[])?; ExternModule::new( vm, record! { - type std::time::Duration => Duration, - type std::time::Instant => Instant, - type std::time::SystemTime => SystemTime, - - unix_epoch => SystemTime(time::UNIX_EPOCH), - - as_secs => primitive!(1, std::time::prim::as_secs), - subsec_nanos => primitive!(1, std::time::prim::subsec_nanos), - instant_now => primitive!(1, std::time::prim::instant_now), - instant_since => primitive!(2, std::time::prim::instant_since), - instant_elapsed => primitive!(1, std::time::prim::instant_elapsed), - system_time_now => primitive!(1, std::time::prim::system_time_now), - system_time_since => primitive!(2, std::time::prim::system_time_since), - system_time_elapsed => primitive!(1, std::time::prim::system_time_elapsed), - - }, + duration => record! { + type std::time::Duration => duration::Duration, + + as_secs => primitive!(1, std::time::prim::duration::as_secs), + subsec_nanos => primitive!(1, std::time::prim::duration::subsec_nanos), + }, + instant => record! { + type std::time::Instant => instant::Instant, + + now => primitive!(1, std::time::prim::instant::now), + duration_since => primitive!(2, std::time::prim::instant::duration_since), + elapsed => primitive!(1, std::time::prim::instant::elapsed), + }, + system_time => record! { + type std::time::SystemTime => system_time::SystemTime, + + unix_epoch => system_time::SystemTime(time::UNIX_EPOCH), + + now => primitive!(1, std::time::prim::system_time::now), + duration_since => primitive!(2, std::time::prim::system_time::duration_since), + elapsed => primitive!(1, std::time::prim::system_time::elapsed), + }, + } ) } From 04b4bf759df2125de1488ea12ea24e6318fd85fc Mon Sep 17 00:00:00 2001 From: Etherian Date: Wed, 11 Sep 2019 19:32:01 -0400 Subject: [PATCH 04/16] add rest of std::time functions --- src/std_lib/time.rs | 136 ++++++++++++++++++++++++++++++++++++++++++-- std/time.glu | 4 ++ 2 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs index 6d7a261db2..71c2a7cbeb 100644 --- a/src/std_lib/time.rs +++ b/src/std_lib/time.rs @@ -13,6 +13,23 @@ use crate::vm::{ ExternModule, }; +const NANOS_PER_SEC: u64 = 1_000_000_000; + +macro_rules! try_convert { + ($val: expr, $msg: expr) => {{ + $val.try_into().map_err(|_| $msg.to_string()).into() + }}; +} + +macro_rules! convert_or_abort { + ($val: expr, $msg: expr) => {{ + match try_convert!($val, $msg) { + RuntimeResult::Return(x) => x, + RuntimeResult::Panic(e) => return RuntimeResult::Panic(e), + } + }}; +} + mod duration { use super::*; @@ -23,16 +40,89 @@ mod duration { #[gluon_trace(skip)] pub(crate) struct Duration(pub(crate) time::Duration); + pub(crate) fn new(secs: VmInt, nanos: VmInt) -> RuntimeResult { + let secs: u64 = convert_or_abort!(secs, "seconds must be non-negative"); + let nanos: u64 = convert_or_abort!(nanos, "nanoseconds must be non-negative"); + let secs = secs.checked_add(nanos / NANOS_PER_SEC); + let nanos = (nanos % NANOS_PER_SEC) as u32; + + match secs { + Some(secs) => RuntimeResult::Return(Duration(time::Duration::new(secs, nanos))), + // should never occur because i64.max_value() + i64.max_value() / 1e9 < u64.max_value() + None => RuntimeResult::Panic("seconds overflowed when creating a new Duration".to_string()), + } + } + + pub(crate) fn from_secs(secs: VmInt) -> RuntimeResult { + new(secs, 0) + } + + pub(crate) fn from_millis(millis: VmInt) -> RuntimeResult { + let millis: u64 = convert_or_abort!(millis, "milliseconds must be non-negative"); + RuntimeResult::Return(Duration(time::Duration::from_millis(millis))) + } + + pub(crate) fn from_micros(micros: VmInt) -> RuntimeResult { + let micros: u64 = convert_or_abort!(micros, "microseconds must be non-negative"); + RuntimeResult::Return(Duration(time::Duration::from_micros(micros))) + } + + pub(crate) fn from_nanos(nanos: VmInt) -> RuntimeResult { + new(0, nanos) + } + pub(crate) fn as_secs(dur: &Duration) -> RuntimeResult { - dur.0.as_secs() - .try_into() - .map_err(|_| String::from("Overflow when trying to convert Duration into seconds")) - .into() + try_convert!(dur.0.as_secs(), "Overflow when trying to convert Duration into seconds") + } + + pub(crate) fn subsec_millis(dur: &Duration) -> VmInt { + dur.0.subsec_millis() as VmInt + } + + pub(crate) fn subsec_micros(dur: &Duration) -> VmInt { + dur.0.subsec_micros() as VmInt } pub(crate) fn subsec_nanos(dur: &Duration) -> VmInt { dur.0.subsec_nanos() as VmInt } + + pub(crate) fn as_millis(dur: &Duration) -> RuntimeResult { + try_convert!(dur.0.as_millis(), "Overflow when trying to convert Duration into milliseconds") + } + + pub(crate) fn as_micros(dur: &Duration) -> RuntimeResult { + try_convert!(dur.0.as_micros(), "Overflow when trying to convert Duration into microseconds") + } + + pub(crate) fn as_nanos(dur: &Duration) -> RuntimeResult { + try_convert!(dur.0.as_nanos(), "Overflow when trying to convert Duration into nanoseconds") + } + + pub(crate) fn checked_add(dur1: &Duration, dur2: &Duration) -> Option { + dur1.0.checked_add(dur2.0).map(Duration) + } + + pub(crate) fn checked_sub(dur1: &Duration, dur2: &Duration) -> Option { + dur1.0.checked_sub(dur2.0).map(Duration) + } + + // should this be Option because it better matches Rust's API or Result because it could fail + // in two different ways? + pub(crate) fn checked_mul(dur1: &Duration, multiplier: VmInt) -> Option { + match multiplier.try_into() { + Ok(n) => dur1.0.checked_mul(n).map(Duration), + Err(_) => None, + } + } + + pub(crate) fn checked_div(dur1: &Duration, divisor: VmInt) -> Option { + match divisor.try_into() { + Ok(n) => dur1.0.checked_div(n).map(Duration), + Err(_) => None, + } + } + } mod instant { @@ -64,6 +154,14 @@ mod instant { pub(crate) fn elapsed(earlier: &Instant) -> Duration { Duration(earlier.0.elapsed()) } + + pub(crate) fn checked_add(moment: &Instant, dur: &Duration) -> Option { + moment.0.checked_add(dur.0).map(Instant) + } + + pub(crate) fn checked_sub(moment: &Instant, dur: &Duration) -> Option { + moment.0.checked_sub(dur.0).map(Instant) + } } mod system_time { @@ -93,6 +191,14 @@ mod system_time { .map(|x| Duration(x)) .map_err(|e| Duration(e.duration())) } + + pub(crate) fn checked_add(moment: &SystemTime, dur: &Duration) -> Option { + moment.0.checked_add(dur.0).map(SystemTime) + } + + pub(crate) fn checked_sub(moment: &SystemTime, dur: &Duration) -> Option { + moment.0.checked_sub(dur.0).map(SystemTime) + } } mod std { @@ -112,8 +218,24 @@ pub fn load(vm: &Thread) -> vm::Result { duration => record! { type std::time::Duration => duration::Duration, + new => primitive!(2, std::time::prim::duration::new), + from_secs => primitive!(1, std::time::prim::duration::from_secs), + from_millis => primitive!(1, std::time::prim::duration::from_millis), + from_micros => primitive!(1, std::time::prim::duration::from_micros), + from_nanos => primitive!(1, std::time::prim::duration::from_nanos), + as_secs => primitive!(1, std::time::prim::duration::as_secs), + subsec_millis => primitive!(1, std::time::prim::duration::subsec_millis), + subsec_micros => primitive!(1, std::time::prim::duration::subsec_micros), subsec_nanos => primitive!(1, std::time::prim::duration::subsec_nanos), + as_millis => primitive!(1, std::time::prim::duration::as_millis), + as_micros => primitive!(1, std::time::prim::duration::as_micros), + as_nanos => primitive!(1, std::time::prim::duration::as_nanos), + + checked_add => primitive!(2, std::time::prim::duration::checked_add), + checked_sub => primitive!(2, std::time::prim::duration::checked_sub), + checked_mul => primitive!(2, std::time::prim::duration::checked_mul), + checked_div => primitive!(2, std::time::prim::duration::checked_div), }, instant => record! { type std::time::Instant => instant::Instant, @@ -121,6 +243,9 @@ pub fn load(vm: &Thread) -> vm::Result { now => primitive!(1, std::time::prim::instant::now), duration_since => primitive!(2, std::time::prim::instant::duration_since), elapsed => primitive!(1, std::time::prim::instant::elapsed), + + checked_add => primitive!(2, std::time::prim::instant::checked_add), + checked_sub => primitive!(2, std::time::prim::instant::checked_sub), }, system_time => record! { type std::time::SystemTime => system_time::SystemTime, @@ -130,6 +255,9 @@ pub fn load(vm: &Thread) -> vm::Result { now => primitive!(1, std::time::prim::system_time::now), duration_since => primitive!(2, std::time::prim::system_time::duration_since), elapsed => primitive!(1, std::time::prim::system_time::elapsed), + + checked_add => primitive!(2, std::time::prim::system_time::checked_add), + checked_sub => primitive!(2, std::time::prim::system_time::checked_sub), }, } ) diff --git a/std/time.glu b/std/time.glu index e1b7bfc352..72a6d6ded9 100644 --- a/std/time.glu +++ b/std/time.glu @@ -2,6 +2,10 @@ let time = import! std.time.prim +// TODO: implement Eq Duration and Ord Duration +// TODO: implement Eq Instant and Ord Instant +// TODO: implement Eq SystemTime and Ord SystemTime + { .. time From 905a3141cb650d20ca56323c4ff1d9eb3c1afc30 Mon Sep 17 00:00:00 2001 From: Etherian Date: Wed, 25 Sep 2019 03:04:33 -0400 Subject: [PATCH 05/16] wrap return of Instant.now & SystemTime.now in IO monad, since they break referential transparency --- src/std_lib/time.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs index 71c2a7cbeb..04c3179ad3 100644 --- a/src/std_lib/time.rs +++ b/src/std_lib/time.rs @@ -151,8 +151,8 @@ mod instant { } } - pub(crate) fn elapsed(earlier: &Instant) -> Duration { - Duration(earlier.0.elapsed()) + pub(crate) fn elapsed(earlier: &Instant) -> IO { + IO::Value(Duration(earlier.0.elapsed())) } pub(crate) fn checked_add(moment: &Instant, dur: &Duration) -> Option { @@ -186,10 +186,10 @@ mod system_time { .map_err(|e| Duration(e.duration())) } - pub(crate) fn elapsed(earlier: &SystemTime) -> Result { - earlier.0.elapsed() - .map(|x| Duration(x)) - .map_err(|e| Duration(e.duration())) + pub(crate) fn elapsed(earlier: &SystemTime) -> IO> { + IO::Value(earlier.0.elapsed() + .map(|x| Duration(x)) + .map_err(|e| Duration(e.duration()))) } pub(crate) fn checked_add(moment: &SystemTime, dur: &Duration) -> Option { From 1c3e5b4ed021bebebbd3029501ff080396ab66f7 Mon Sep 17 00:00:00 2001 From: Etherian Date: Sat, 28 Sep 2019 22:23:34 -0400 Subject: [PATCH 06/16] add eq and lt functions to each type --- src/std_lib/time.rs | 87 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs index 04c3179ad3..25722d8bf9 100644 --- a/src/std_lib/time.rs +++ b/src/std_lib/time.rs @@ -1,9 +1,6 @@ //! Module containing bindings to rust's `std::time` module. -use crate::real_std::{ - time, - convert::TryInto, -}; +use crate::real_std::{convert::TryInto, time}; use crate::vm::{ self, @@ -49,7 +46,9 @@ mod duration { match secs { Some(secs) => RuntimeResult::Return(Duration(time::Duration::new(secs, nanos))), // should never occur because i64.max_value() + i64.max_value() / 1e9 < u64.max_value() - None => RuntimeResult::Panic("seconds overflowed when creating a new Duration".to_string()), + None => { + RuntimeResult::Panic("seconds overflowed when creating a new Duration".to_string()) + } } } @@ -72,7 +71,10 @@ mod duration { } pub(crate) fn as_secs(dur: &Duration) -> RuntimeResult { - try_convert!(dur.0.as_secs(), "Overflow when trying to convert Duration into seconds") + try_convert!( + dur.0.as_secs(), + "Overflow when trying to convert Duration into seconds" + ) } pub(crate) fn subsec_millis(dur: &Duration) -> VmInt { @@ -88,15 +90,24 @@ mod duration { } pub(crate) fn as_millis(dur: &Duration) -> RuntimeResult { - try_convert!(dur.0.as_millis(), "Overflow when trying to convert Duration into milliseconds") + try_convert!( + dur.0.as_millis(), + "Overflow when trying to convert Duration into milliseconds" + ) } pub(crate) fn as_micros(dur: &Duration) -> RuntimeResult { - try_convert!(dur.0.as_micros(), "Overflow when trying to convert Duration into microseconds") + try_convert!( + dur.0.as_micros(), + "Overflow when trying to convert Duration into microseconds" + ) } pub(crate) fn as_nanos(dur: &Duration) -> RuntimeResult { - try_convert!(dur.0.as_nanos(), "Overflow when trying to convert Duration into nanoseconds") + try_convert!( + dur.0.as_nanos(), + "Overflow when trying to convert Duration into nanoseconds" + ) } pub(crate) fn checked_add(dur1: &Duration, dur2: &Duration) -> Option { @@ -109,24 +120,31 @@ mod duration { // should this be Option because it better matches Rust's API or Result because it could fail // in two different ways? - pub(crate) fn checked_mul(dur1: &Duration, multiplier: VmInt) -> Option { + pub(crate) fn checked_mul(dur: &Duration, multiplier: VmInt) -> Option { match multiplier.try_into() { - Ok(n) => dur1.0.checked_mul(n).map(Duration), + Ok(n) => dur.0.checked_mul(n).map(Duration), Err(_) => None, } } - pub(crate) fn checked_div(dur1: &Duration, divisor: VmInt) -> Option { + pub(crate) fn checked_div(dur: &Duration, divisor: VmInt) -> Option { match divisor.try_into() { - Ok(n) => dur1.0.checked_div(n).map(Duration), + Ok(n) => dur.0.checked_div(n).map(Duration), Err(_) => None, } } + pub(crate) fn eq(dur1: &Duration, dur2: &Duration) -> bool { + dur1.0 == dur2.0 + } + + pub(crate) fn lt(dur1: &Duration, dur2: &Duration) -> bool { + dur1.0 < dur2.0 + } } mod instant { - use super::{ *, duration::Duration }; + use super::{duration::Duration, *}; #[derive(Clone, Debug, Userdata, Trace, VmType)] #[gluon_userdata(clone)] @@ -162,10 +180,18 @@ mod instant { pub(crate) fn checked_sub(moment: &Instant, dur: &Duration) -> Option { moment.0.checked_sub(dur.0).map(Instant) } + + pub(crate) fn eq(moment1: &Instant, moment2: &Instant) -> bool { + moment1.0 == moment2.0 + } + + pub(crate) fn lt(moment1: &Instant, moment2: &Instant) -> bool { + moment1.0 < moment2.0 + } } mod system_time { - use super::{ *, duration::Duration }; + use super::{duration::Duration, *}; #[derive(Clone, Debug, Userdata, Trace, VmType)] #[gluon_userdata(clone)] @@ -181,15 +207,19 @@ mod system_time { /// Returns `Ok(later - earlier)` if `later` is the same as or later than `earlier`. /// Returns `Err(earlier - later)` if `later` is earlier than `earlier`. pub(crate) fn duration_since(later : &SystemTime, earlier : &SystemTime) -> Result { - later.0.duration_since(earlier.0) + later.0 + .duration_since(earlier.0) .map(|x| Duration(x)) .map_err(|e| Duration(e.duration())) } pub(crate) fn elapsed(earlier: &SystemTime) -> IO> { - IO::Value(earlier.0.elapsed() - .map(|x| Duration(x)) - .map_err(|e| Duration(e.duration()))) + IO::Value( + earlier.0 + .elapsed() + .map(|x| Duration(x)) + .map_err(|e| Duration(e.duration())), + ) } pub(crate) fn checked_add(moment: &SystemTime, dur: &Duration) -> Option { @@ -199,6 +229,14 @@ mod system_time { pub(crate) fn checked_sub(moment: &SystemTime, dur: &Duration) -> Option { moment.0.checked_sub(dur.0).map(SystemTime) } + + pub(crate) fn eq(moment1: &SystemTime, moment2: &SystemTime) -> bool { + moment1.0 == moment2.0 + } + + pub(crate) fn lt(moment1: &SystemTime, moment2: &SystemTime) -> bool { + moment1.0 < moment2.0 + } } mod std { @@ -236,6 +274,9 @@ pub fn load(vm: &Thread) -> vm::Result { checked_sub => primitive!(2, std::time::prim::duration::checked_sub), checked_mul => primitive!(2, std::time::prim::duration::checked_mul), checked_div => primitive!(2, std::time::prim::duration::checked_div), + + eq => primitive!(2, std::time::prim::duration::eq), + lt => primitive!(2, std::time::prim::duration::lt), }, instant => record! { type std::time::Instant => instant::Instant, @@ -246,6 +287,9 @@ pub fn load(vm: &Thread) -> vm::Result { checked_add => primitive!(2, std::time::prim::instant::checked_add), checked_sub => primitive!(2, std::time::prim::instant::checked_sub), + + eq => primitive!(2, std::time::prim::instant::eq), + lt => primitive!(2, std::time::prim::instant::lt), }, system_time => record! { type std::time::SystemTime => system_time::SystemTime, @@ -258,7 +302,10 @@ pub fn load(vm: &Thread) -> vm::Result { checked_add => primitive!(2, std::time::prim::system_time::checked_add), checked_sub => primitive!(2, std::time::prim::system_time::checked_sub), + + eq => primitive!(2, std::time::prim::system_time::eq), + lt => primitive!(2, std::time::prim::system_time::lt), }, - } + }, ) } From f50c72f52214ea1ef02259d6aa8504cf2dd260ed Mon Sep 17 00:00:00 2001 From: Etherian Date: Sun, 29 Sep 2019 01:28:07 -0400 Subject: [PATCH 07/16] reformat std.time and add docs for std.time.duration --- std/time.glu | 12 -- std/time/duration.glu | 386 +++++++++++++++++++++++++++++++++++++++ std/time/instant.glu | 42 +++++ std/time/system_time.glu | 42 +++++ 4 files changed, 470 insertions(+), 12 deletions(-) delete mode 100644 std/time.glu create mode 100644 std/time/duration.glu create mode 100644 std/time/instant.glu create mode 100644 std/time/system_time.glu diff --git a/std/time.glu b/std/time.glu deleted file mode 100644 index 72a6d6ded9..0000000000 --- a/std/time.glu +++ /dev/null @@ -1,12 +0,0 @@ -//! Time-related functionality - -let time = import! std.time.prim - -// TODO: implement Eq Duration and Ord Duration -// TODO: implement Eq Instant and Ord Instant -// TODO: implement Eq SystemTime and Ord SystemTime - -{ - .. - time -} diff --git a/std/time/duration.glu b/std/time/duration.glu new file mode 100644 index 0000000000..fabd60dc04 --- /dev/null +++ b/std/time/duration.glu @@ -0,0 +1,386 @@ +//! Time-related functionality +// Documentation in this module is mostly modified from Rust's std::time crate. + +let { Ordering } = import! std.types +let { Eq, Ord } = import! std.cmp +let duration @ { Duration } = import! std.time.prim.duration + +let eq : Eq Duration = {(==) = duration.eq} + +let ord : Ord Duration = + let compare x y = + if duration.eq x y then + EQ + else if duration.lt x y then + LT + else + GT + + {eq, compare} + +{ + /// A `Duration` represents a span of time. + /// + /// Each `Duration` is composed of a whole number of seconds and a fractional part + /// represented in nanoseconds. If the underlying system does not support + /// nanosecond-level precision, APIs binding a system timeout will typically round + /// up the number of nanoseconds. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let five_seconds = duration.from_secs 5 + /// + /// seq assert_eq 5 (duration.as_secs five_seconds) + /// seq assert_eq 0 (duration.subsec_nanos five_seconds) + /// assert_eq (Some 10) + /// (duration.checked_add five_seconds five_seconds |> map duration.as_secs) + /// ``` + Duration, + + /// Creates a new `Duration` from the specified number of whole seconds and + /// additional nanoseconds. + /// + /// If the number of nanoseconds is 1 billion (the number of nanoseconds in a + /// second) or greater, then it will carry over into the seconds provided. + /// + /// # Panics + /// + /// This function panics if the specified number of seconds or nanoseconds are + /// negative. + /// + /// # Examples + /// + /// ``` + /// let { duration } = import! std.time + /// + /// let five_and_a_half_seconds = duration.new 5 500000000 + /// ``` + new = duration.new, + + /// Creates a new `Duration` from the specified number of whole seconds. + /// + /// # Panics + /// + /// This function panics if the specified number of seconds is negative. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let five_seconds = duration.from_secs 5 + /// + /// seq assert_eq 5 (duration.as_secs five_seconds) + /// assert_eq 0 (duration.subsec_nanos five_seconds) + /// ``` + from_secs = duration.from_secs, + + /// Creates a new `Duration` from the specified number of whole milliseconds. + /// + /// # Panics + /// + /// This function panics if the specified number of milliseconds is negative. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let two_and_a_half_seconds = duration.from_millis 2500 + /// + /// seq assert_eq 2 (duration.as_secs two_and_a_half_seconds) + /// assert_eq 500000000 (duration.subsec_nanos two_and_a_half_seconds) + /// ``` + from_millis = duration.from_millis, + + /// Creates a new `Duration` from the specified number of whole microseconds. + /// + /// # Panics + /// + /// This function panics if the specified number of microseconds is negative. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let one_and_a_little_seconds = duration.from_micros 1000002 + /// + /// seq assert_eq 1 (duration.as_secs one_and_a_little_seconds) + /// assert_eq 2000 (duration.subsec_nanos one_and_a_little_seconds) + /// ``` + from_micros = duration.from_micros, + + /// Creates a new `Duration` from the specified number of whole nanoseconds. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let four_and_a_half_seconds = duration.from_nanos 4500000000 + /// + /// seq assert_eq 4 (duration.as_secs four_and_a_half_seconds) + /// assert_eq 500000000 (duration.subsec_nanos four_and_a_half_seconds) + /// ``` + from_nanos = duration.from_nanos, + + /// Returns the number of *whole* seconds contained by this `Duration`. + /// + /// The returned value does not include the fractional (nanosecond) part of the + /// duration, which can be obtained using `subsec_nanos`. + /// + /// # Panics + /// + /// This function will panic if the resultant number of seconds is greater than + /// `int.max_value` + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.new 5 730023852 + /// + /// assert_eq 5 (duration.as_secs dur) + /// ``` + /// + /// To determine the total number of seconds represented by the `Duration`, + /// use `as_secs` in combination with `subsec_nanos`: + /// + /// ``` + /// let float = import! std.float + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.new 5 730023852 + /// + /// assert_eq 5.730023852 + /// (float.from_int (duration.as_secs dur) + /// + float.from_int (duration.subsec_nanos dur) * 0.000000001) + /// ``` + as_secs = duration.as_secs, + + /// Returns the fractional part of this `Duration`, in whole milliseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by milliseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is always less than one thousand). + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.from_millis 5432 + /// + /// seq assert_eq 5 (duration.as_secs dur) + /// assert_eq 432 (duration.subsec_millis dur) + /// ``` + subsec_millis = duration.subsec_millis, + + /// Returns the fractional part of this `Duration`, in whole microseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by microseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is always less than one million). + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.from_micros 1234567 + /// + /// seq assert_eq 1 (duration.as_secs dur) + /// assert_eq 234567 (duration.subsec_micros dur) + /// ``` + subsec_micros = duration.subsec_micros, + + /// Returns the fractional part of this `Duration`, in whole nanoseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by microseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is always less than one billion). + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.from_millis 5432 + /// + /// seq assert_eq 5 (duration.as_secs dur) + /// assert_eq 432000000 (duration.subsec_nanos dur) + /// ``` + subsec_nanos = duration.subsec_nanos, + + /// Returns the total number of whole milliseconds contained by this `Duration`. + /// + /// # Panics + /// + /// This function will panic if the resultant number of milliseconds is greater + /// than `int.max_value` + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.new 3 141592653 + /// + /// seq assert_eq 3141 (duration.as_millis dur) + /// ``` + as_millis = duration.as_millis, + + /// Returns the total number of whole microseconds contained by this `Duration`. + /// + /// # Panics + /// + /// This function will panic if the resultant number of microseconds is greater + /// than `int.max_value` + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.new 3 141592653 + /// + /// assert_eq 3141592 (duration.as_micros dur) + /// ``` + as_micros = duration.as_micros, + + /// Returns the total number of nanoseconds contained by this `Duration`. + /// + /// # Panics + /// + /// This function will panic if the resultant number of nanoseconds is greater + /// than `int.max_value` + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.new 3 141592653 + /// + /// assert_eq 3141592653 (duration.as_nanos dur) + /// ``` + as_nanos = duration.as_nanos, + + /// Checked `Duration` addition. Computes `x + y`, returning `None` if overflow + /// occurred. + /// + /// # Examples + /// + /// ``` + /// let int = import! std.int + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur_x = duration.new 3 500000000 + /// let dur_y = duration.new 5 250000000 + /// let dur_max = duration.new int.max_value 250000000 + /// + /// seq assert_eq (Some (duration.new 8 750000000)) + /// (duration.checked_add dur_x dur_y) + /// assert_eq None + /// (duration.checked_add dur_max dur_y) + /// ``` + checked_add = duration.checked_add, + + /// Checked `Duration` subtraction. Computes `x - y`, returning `None` if the + /// result would be negative. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur_small = duration.new 3 500000000 + /// let dur_big = duration.new 5 250000000 + /// + /// seq assert_eq (Some (duration.new 1 750000000)) + /// (duration.checked_sub dur_big dur_small) + /// assert_eq None + /// (duration.checked_sub dur_small dur_big) + /// ``` + checked_sub = duration.checked_sub, + + /// Checked multiplication of a `Duration` by an integer. Computes `dur * n`, + /// returning `None` if `n` is negative or overflow occurred. + /// + /// # Examples + /// + /// ``` + /// let int = import! std.int + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.new 3 500000000 + /// let dur_max = duration.new int.max_value 250000000 + /// + /// seq assert_eq (Some (duration.new 17 500000000)) + /// (duration.checked_mul dur 5) + /// seq assert_eq None + /// (duration.checked_mul dur -5) + /// assert_eq None + /// (duration.checked_mul dur_max 5) + /// ``` + checked_mul = duration.checked_mul, + + /// Checked division of a `Duration` by an integer. Computes `dur / n`, + /// returning `None` if `n == 0` or `n` is negative. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.effect + /// let { assert_eq, ? } = import! std.test + /// let { duration } = import! std.time + /// + /// let dur = duration.new 3 500000000 + /// + /// seq assert_eq (Some (duration.new 1 750000000)) + /// (duration.checked_div dur 2) + /// assert_eq None + /// (duration.checked_div dur 0) + /// ``` + checked_div = duration.checked_div, + + eq, + ord, +} diff --git a/std/time/instant.glu b/std/time/instant.glu new file mode 100644 index 0000000000..1506ba9bd0 --- /dev/null +++ b/std/time/instant.glu @@ -0,0 +1,42 @@ +//! Time-related functionality +// Documentation in this module is mostly modified from Rust's std::time crate. + +let { Ordering } = import! std.types +let { Eq, Ord } = import! std.cmp +let instant @ { Instant } = import! std.time.prim.instant + +let eq : Eq Instant = {(==) = instant.eq} + +let ord : Ord Instant = + let compare x y = + if instant.eq x y then + EQ + else if instant.lt x y then + LT + else + GT + + {eq, compare} + +{ + /// Docs go here + Instant, + + /// Docs + now = instant.now, + + /// Docs + duration_since = instant.duration_since + + /// Docs + elapsed = instant.elapsed, + + /// Docs + checked_add = instant.checked_add + + /// Docs + checked_sub = instant.checked_sub + + eq, + ord, +} diff --git a/std/time/system_time.glu b/std/time/system_time.glu new file mode 100644 index 0000000000..8fe575eca9 --- /dev/null +++ b/std/time/system_time.glu @@ -0,0 +1,42 @@ +//! Time-related functionality +// Documentation in this module is mostly modified from Rust's std::time crate. + +let { Ordering } = import! std.types +let { Eq, Ord } = import! std.cmp +let system_time @ { SystemTime } = import! std.time.prim.system_time + +let eq : Eq SystemTime = {(==) = system_time.eq} + +let ord : Ord SystemTime = + let compare x y = + if system_time.eq x y then + EQ + else if system_time.lt x y then + LT + else + GT + + {eq, compare} + +{ + /// Docs go here + SystemTime, + + /// Docs + now = system_time.now, + + /// Docs + duration_since = system_time.duration_since + + /// Docs + elapsed = system_time.elapsed, + + /// Docs + checked_add = system_time.checked_add + + /// Docs + checked_sub = system_time.checked_sub + + eq, + ord, +} From 593a376d75c696f73d3abde82d963a74cdd8167d Mon Sep 17 00:00:00 2001 From: Etherian Date: Tue, 1 Oct 2019 02:58:30 -0400 Subject: [PATCH 08/16] fix imports in std.time modules --- std/time/duration.glu | 3 ++- std/time/instant.glu | 3 ++- std/time/system_time.glu | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/std/time/duration.glu b/std/time/duration.glu index fabd60dc04..a9f49b8740 100644 --- a/std/time/duration.glu +++ b/std/time/duration.glu @@ -3,7 +3,8 @@ let { Ordering } = import! std.types let { Eq, Ord } = import! std.cmp -let duration @ { Duration } = import! std.time.prim.duration +let { duration } = import! std.time.prim +let { Duration } = duration let eq : Eq Duration = {(==) = duration.eq} diff --git a/std/time/instant.glu b/std/time/instant.glu index 1506ba9bd0..f020662d95 100644 --- a/std/time/instant.glu +++ b/std/time/instant.glu @@ -3,7 +3,8 @@ let { Ordering } = import! std.types let { Eq, Ord } = import! std.cmp -let instant @ { Instant } = import! std.time.prim.instant +let { instant } = import! std.time.prim +let { Instant } = instant let eq : Eq Instant = {(==) = instant.eq} diff --git a/std/time/system_time.glu b/std/time/system_time.glu index 8fe575eca9..83369e4957 100644 --- a/std/time/system_time.glu +++ b/std/time/system_time.glu @@ -3,7 +3,8 @@ let { Ordering } = import! std.types let { Eq, Ord } = import! std.cmp -let system_time @ { SystemTime } = import! std.time.prim.system_time +let { system_time } = import! std.time.prim +let { SystemTime } = system_time let eq : Eq SystemTime = {(==) = system_time.eq} From 30e5cfba329712ce1592137f98de4a2954f7eeed Mon Sep 17 00:00:00 2001 From: Etherian Date: Sun, 13 Oct 2019 23:36:43 -0400 Subject: [PATCH 09/16] various cleanups and fixes --- src/std_lib/time.rs | 15 +++++++-------- std/time.glu | 17 +++++++++++++++++ std/time/duration.glu | 2 +- std/time/instant.glu | 8 ++++---- std/time/system_time.glu | 8 ++++---- 5 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 std/time.glu diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs index 25722d8bf9..45276ec872 100644 --- a/src/std_lib/time.rs +++ b/src/std_lib/time.rs @@ -153,14 +153,13 @@ mod instant { #[gluon_trace(skip)] pub(crate) struct Instant(pub(crate) time::Instant); - pub(crate) fn now(_: ()) -> IO { + pub(crate) fn now() -> IO { IO::Value(Instant(time::Instant::now())) } - /// Returns `Some(later - earlier)` if `later` is the same as or later than `earlier`. - /// Returns None otherwise. - pub(crate) fn duration_since(later: &Instant, earlier: &Instant) -> Option { - // Note: replace with checked_duration_since when 1.38 is stable + // Note: The parameters are reversed relative to the underlying standard library function + pub(crate) fn duration_since(earlier: &Instant, later: &Instant) -> Option { + // Note: replace with checked_duration_since when it lands in Stable if later.0 >= earlier.0 { // should never panic Some(Duration(later.0.duration_since(earlier.0))) @@ -200,7 +199,7 @@ mod system_time { #[gluon_trace(skip)] pub(crate) struct SystemTime(pub(crate) time::SystemTime); - pub(crate) fn now(_: ()) -> IO { + pub(crate) fn now() -> IO { IO::Value(SystemTime(time::SystemTime::now())) } @@ -281,7 +280,7 @@ pub fn load(vm: &Thread) -> vm::Result { instant => record! { type std::time::Instant => instant::Instant, - now => primitive!(1, std::time::prim::instant::now), + now => primitive!(0, std::time::prim::instant::now), duration_since => primitive!(2, std::time::prim::instant::duration_since), elapsed => primitive!(1, std::time::prim::instant::elapsed), @@ -296,7 +295,7 @@ pub fn load(vm: &Thread) -> vm::Result { unix_epoch => system_time::SystemTime(time::UNIX_EPOCH), - now => primitive!(1, std::time::prim::system_time::now), + now => primitive!(0, std::time::prim::system_time::now), duration_since => primitive!(2, std::time::prim::system_time::duration_since), elapsed => primitive!(1, std::time::prim::system_time::elapsed), diff --git a/std/time.glu b/std/time.glu new file mode 100644 index 0000000000..c934d7b016 --- /dev/null +++ b/std/time.glu @@ -0,0 +1,17 @@ +//! Time-related functionality +let duration = import! std.time.duration +let instant = import! std.time.instant +let system_time = import! std.time.system_time + +{ + duration, + instant, + system_time, + + duration_eq = duration.eq, + duration_ord = duration.ord, + instant_eq = instant.eq, + instant_ord = instant.ord, + system_time_eq = system_time.eq, + system_time_ord = system_time.ord, +} diff --git a/std/time/duration.glu b/std/time/duration.glu index a9f49b8740..ab5361348e 100644 --- a/std/time/duration.glu +++ b/std/time/duration.glu @@ -1,4 +1,4 @@ -//! Time-related functionality +//! A `Duration` type for representing and working with spans of time // Documentation in this module is mostly modified from Rust's std::time crate. let { Ordering } = import! std.types diff --git a/std/time/instant.glu b/std/time/instant.glu index f020662d95..0c61b26e06 100644 --- a/std/time/instant.glu +++ b/std/time/instant.glu @@ -1,4 +1,4 @@ -//! Time-related functionality +//! A measurement on a monotonically-nondecreasing clock. Opaque and useful only with `Duration`. // Documentation in this module is mostly modified from Rust's std::time crate. let { Ordering } = import! std.types @@ -27,16 +27,16 @@ let ord : Ord Instant = now = instant.now, /// Docs - duration_since = instant.duration_since + duration_since = instant.duration_since, /// Docs elapsed = instant.elapsed, /// Docs - checked_add = instant.checked_add + checked_add = instant.checked_add, /// Docs - checked_sub = instant.checked_sub + checked_sub = instant.checked_sub, eq, ord, diff --git a/std/time/system_time.glu b/std/time/system_time.glu index 83369e4957..092bf5caf0 100644 --- a/std/time/system_time.glu +++ b/std/time/system_time.glu @@ -1,4 +1,4 @@ -//! Time-related functionality +//! A measurement of the system clock. Not as consistent as `Instant`, but can represent a specific moment in history. // Documentation in this module is mostly modified from Rust's std::time crate. let { Ordering } = import! std.types @@ -27,16 +27,16 @@ let ord : Ord SystemTime = now = system_time.now, /// Docs - duration_since = system_time.duration_since + duration_since = system_time.duration_since, /// Docs elapsed = system_time.elapsed, /// Docs - checked_add = system_time.checked_add + checked_add = system_time.checked_add, /// Docs - checked_sub = system_time.checked_sub + checked_sub = system_time.checked_sub, eq, ord, From f38694d131b5e85771b7ee3ddf312a2a7e02ce2d Mon Sep 17 00:00:00 2001 From: Etherian Date: Fri, 25 Oct 2019 23:26:16 -0400 Subject: [PATCH 10/16] fix(std): remove panic condition of time.instant.elapsed --- src/std_lib/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs index 45276ec872..aa02ca6285 100644 --- a/src/std_lib/time.rs +++ b/src/std_lib/time.rs @@ -168,8 +168,8 @@ mod instant { } } - pub(crate) fn elapsed(earlier: &Instant) -> IO { - IO::Value(Duration(earlier.0.elapsed())) + pub(crate) fn elapsed(earlier: &Instant) -> IO> { + IO::Value(duration_since(earlier, &Instant(time::Instant::now()))) } pub(crate) fn checked_add(moment: &Instant, dur: &Duration) -> Option { From 13066ca1992296cf8fd6bb7ba7e7f70a6b2599ef Mon Sep 17 00:00:00 2001 From: Etherian Date: Thu, 2 Jul 2020 00:23:34 -0400 Subject: [PATCH 11/16] add docs for std.time.instant --- std/time/instant.glu | 138 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 9 deletions(-) diff --git a/std/time/instant.glu b/std/time/instant.glu index 0c61b26e06..88e219501e 100644 --- a/std/time/instant.glu +++ b/std/time/instant.glu @@ -20,22 +20,142 @@ let ord : Ord Instant = {eq, compare} { - /// Docs go here + /// A measurement of a monotonically nondecreasing clock. + /// Opaque and useful only with `Duration`. + /// + /// Instants are always guaranteed to be no less than any previously measured + /// instant when created, and are often useful for tasks such as measuring + /// benchmarks or timing how long an operation takes. + /// + /// Note, however, that instants are not guaranteed to be **steady**. In other + /// words, each tick of the underlying clock may not be the same length (e.g. + /// some seconds may be longer than others). An instant may jump forwards or + /// experience time dilation (slow down or speed up), but it will never go + /// backwards. + /// + /// Instants are opaque types that can only be compared to one another. There is + /// no method to get "the number of seconds" from an instant. Instead, it only + /// allows measuring the duration between two instants (or comparing two + /// instants). + /// + /// The size of an `Instant` struct may vary depending on the target operating + /// system. + /// + /// Example: + /// + /// ``` + /// let { print, ? } = import! std.io + /// let { assert_eq, ? } = import! std.test + /// let { duration, instant } = import! std.time + /// + /// let long_computation x : [Num a] -> a -> a = x * x + /// + /// do start = instant.now + /// let result = long_computation 12 + /// do time_taken = instant.elapsed start + /// print << show << duration.as_nanos time_taken + /// ``` Instant, - - /// Docs + + /// Returns an instant corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// let { wrap } = import! std.applicative + /// let { ? } = import! std.effect + /// let { assert, ? } = import! std.test + /// let { instant, ? } = import! std.time + /// + /// do moment1 = instant.now + /// do moment2 = instant.now + /// wrap (assert (moment1 <= moment2)) + /// ``` now = instant.now, - - /// Docs + + /// Returns the amount of time elapsed between the first instant and the second, + /// or None if the second instant is earlier than the first. (The order of the + /// parameters is flipped relative to the Rust standard library function.) + /// + /// # Examples + /// + /// ``` + /// let { (<|) } = import! std.function + /// let { wrap } = import! std.applicative + /// let { assert, assert_success, ? } = import! std.test + /// let { Eff, ? } = import! std.effect + /// let { Error, some_or_throw, ? } = import! std.effect.error + /// let { Lift, lift, ? } = import! std.effect.lift + /// let { instant, duration, ? } = import! std.time + /// + /// let example : Eff [| lift: Lift IO, error: Error () | r |] () = + /// do moment1 = lift instant.now + /// do moment2 = lift instant.now + /// do dur = some_or_throw () <| instant.duration_since moment1 moment2 + /// wrap <| assert (dur >= (duration.from_secs 0)) + /// assert_success example + /// ``` duration_since = instant.duration_since, - /// Docs + /// Returns the amount of time elapsed since the given `Instant` was created + /// or None if the current time is earlier than the `Instant`, which can + /// happen if an `Instant` is produced synthetically. + /// + /// # Examples + /// + /// ``` + /// let { ? } = import! std.unit + /// let { (<|) } = import! std.function + /// let { wrap } = import! std.applicative + /// let { (=<<) } = import! std.monad + /// let { assert, assert_success, ? } = import! std.test + /// let { Eff, ? } = import! std.effect + /// let { Error, some_or_throw, ? } = import! std.effect.error + /// let { Lift, lift, ? } = import! std.effect.lift + /// let { ? } = import! std.io + /// let { instant, duration, ? } = import! std.time + /// + /// let example : Eff [| lift: Lift IO, error: Error () | r |] () = + /// do dur = some_or_throw () =<< lift (instant.elapsed =<< instant.now) + /// wrap <| assert (dur >= (duration.from_secs 0)) + /// assert_success example + /// ``` elapsed = instant.elapsed, - - /// Docs + + /// Returns `Some t` where `t` is the time `moment + duration` if `t` can be + /// represented as an `Instant` (which means it's inside the bounds of the + /// underlying data structure) and `None` otherwise. + /// + /// # Examples + /// + /// ``` + /// let { (<|) } = import! std.function + /// let { assert_some, ? } = import! std.test + /// let { lift, ? } = import! std.effect.lift + /// let { ? } = import! std.io + /// let { instant, duration, ? } = import! std.time + /// + /// do moment = lift instant.now + /// assert_some <| instant.checked_add moment (duration.from_secs 3) + /// ``` checked_add = instant.checked_add, - /// Docs + /// Returns `Some t` where `t` is the time `moment - duration` if `t` can be + /// represented as an `Instant` (which means it's inside the bounds of the + /// underlying data structure) and `None` otherwise. + /// + /// # Examples + /// + /// ``` + /// let { (<|) } = import! std.function + /// let { assert_some, ? } = import! std.test + /// let { lift, ? } = import! std.effect.lift + /// let { ? } = import! std.io + /// let { instant, duration, ? } = import! std.time + /// + /// do moment = lift instant.now + /// assert_some <| instant.checked_sub moment (duration.from_secs 3) + /// ``` checked_sub = instant.checked_sub, eq, From 4d6b6f55d56466bd1954dc8e3670045b2375e856 Mon Sep 17 00:00:00 2001 From: Etherian Date: Sun, 6 Sep 2020 02:20:30 -0400 Subject: [PATCH 12/16] feat(std): add saturating_duration_since to instant and system_time --- src/std_lib/time.rs | 48 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/std_lib/time.rs b/src/std_lib/time.rs index aa02ca6285..5df2b8b2a1 100644 --- a/src/std_lib/time.rs +++ b/src/std_lib/time.rs @@ -158,17 +158,25 @@ mod instant { } // Note: The parameters are reversed relative to the underlying standard library function - pub(crate) fn duration_since(earlier: &Instant, later: &Instant) -> Option { - // Note: replace with checked_duration_since when it lands in Stable - if later.0 >= earlier.0 { - // should never panic - Some(Duration(later.0.duration_since(earlier.0))) - } else { - None - } + pub(crate) fn duration_since(earlier: &Instant, later: &Instant) -> Result { + // Should never panic because either earlier <= later or later > earlier + later.0 + .checked_duration_since(earlier.0) + .map(Duration) + .ok_or_else( || + earlier.0 + .checked_duration_since(later.0) + .map(Duration) + .unwrap(), + ) + } + + // Note: The parameters are reversed relative to the underlying standard library function + pub(crate) fn saturating_duration_since(earlier: &Instant, later: &Instant) -> Duration { + Duration(later.0.saturating_duration_since(earlier.0)) } - pub(crate) fn elapsed(earlier: &Instant) -> IO> { + pub(crate) fn elapsed(earlier: &Instant) -> IO> { IO::Value(duration_since(earlier, &Instant(time::Instant::now()))) } @@ -203,15 +211,33 @@ mod system_time { IO::Value(SystemTime(time::SystemTime::now())) } + // Note: The parameters are reversed relative to the underlying standard library function /// Returns `Ok(later - earlier)` if `later` is the same as or later than `earlier`. /// Returns `Err(earlier - later)` if `later` is earlier than `earlier`. - pub(crate) fn duration_since(later : &SystemTime, earlier : &SystemTime) -> Result { + pub(crate) fn duration_since( + earlier: &SystemTime, + later: &SystemTime, + ) -> Result { later.0 .duration_since(earlier.0) .map(|x| Duration(x)) .map_err(|e| Duration(e.duration())) } + // Note: The parameters are reversed relative to the underlying standard library function + /// Returns `later - earlier` if `later` is the same as or later than `earlier`. + /// Returns `0` if `later` is earlier than `earlier`. + pub(crate) fn saturating_duration_since( + earlier: &SystemTime, + later: &SystemTime + ) -> Duration { + Duration( + later.0 + .duration_since(earlier.0) + .unwrap_or(time::Duration::new(0, 0)), + ) + } + pub(crate) fn elapsed(earlier: &SystemTime) -> IO> { IO::Value( earlier.0 @@ -282,6 +308,7 @@ pub fn load(vm: &Thread) -> vm::Result { now => primitive!(0, std::time::prim::instant::now), duration_since => primitive!(2, std::time::prim::instant::duration_since), + saturating_duration_since => primitive!(2, std::time::prim::instant::saturating_duration_since), elapsed => primitive!(1, std::time::prim::instant::elapsed), checked_add => primitive!(2, std::time::prim::instant::checked_add), @@ -297,6 +324,7 @@ pub fn load(vm: &Thread) -> vm::Result { now => primitive!(0, std::time::prim::system_time::now), duration_since => primitive!(2, std::time::prim::system_time::duration_since), + saturating_duration_since => primitive!(2, std::time::prim::system_time::saturating_duration_since), elapsed => primitive!(1, std::time::prim::system_time::elapsed), checked_add => primitive!(2, std::time::prim::system_time::checked_add), From 1bd60a7046c29fc8f0ef60af07fecba4c83d9d1d Mon Sep 17 00:00:00 2001 From: Etherian Date: Sun, 6 Sep 2020 02:25:57 -0400 Subject: [PATCH 13/16] doc(std): add docs to system_time.glu --- std/time/system_time.glu | 180 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 9 deletions(-) diff --git a/std/time/system_time.glu b/std/time/system_time.glu index 092bf5caf0..c36d147e06 100644 --- a/std/time/system_time.glu +++ b/std/time/system_time.glu @@ -20,22 +20,184 @@ let ord : Ord SystemTime = {eq, compare} { - /// Docs go here + /// A measurement of the system clock, useful for talking to external + /// entities like the file system or other processes. + /// + /// Distinct from the `Instant` type, this time measurement **is not + /// monotonic**. This means that you can save a file to the file system, + /// then save another file to the file system, **and the second file have a + /// `SystemTime` measurement earlier than the first**. In other words, an + /// operation that happens after another operation in real time may have an + /// earlier `SystemTime`! + /// + /// Although a `SystemTime` cannot be directly inspected, the `unix_epoch` + /// constant is provided in this module as an anchor in time to learn + /// information about a `SystemTime`. By calculating the duration from this + /// fixed point in time, a `SystemTime` can be converted to a human-readable + /// time, or perhaps some other string representation. SystemTime, - - /// Docs + + /// A `SystemTime` representing the date 1970-01-01 00:00:00 UTC. Using + /// `duration_since unix_epoch` on an existing `SystemTime` instance + /// can tell how far away from this point in time a measurement + /// lies, and using `checked_add unix_epoch duration` can be used to create + /// a `SystemTime` instance to represent another fixed point in time. + /// + /// # Examples + /// + /// ``` + /// let { (<|), (<<) } = import! std.function + /// let { wrap } = import! std.applicative + /// let { Result, ? } = import! std.result + /// let { ? } = import! std.effect + /// let { lift, ? } = import! std.effect.lift + /// let { println, ? } = import! std.io + /// let { system_time, duration, ? } = import! std.time + /// + /// do this_moment = lift system_time.now + /// let diff = system_time.duration_since system_time.unix_epoch this_moment + /// // match diff with + /// // | Ok x -> lift <| println <| "1970-01-01 00:00:00 UTC was " + /// // ++ (show << duration.as_secs) x + /// // ++ " seconds ago!" + /// // | Err _ -> lift <| println "SystemTime before UNIX EPOCH!" + /// wrap () + /// ``` + unix_epoch = system_time.unix_epoch, + + /// Returns a `SystemTime` corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// let { (<|) } = import! std.function + /// let { wrap } = import! std.applicative + /// let int = import! std.int + /// let array = import! std.array + /// let { unwrap_ok_or } = import! std.result + /// let { ? } = import! std.effect + /// let { lift, ? } = import! std.effect.lift + /// let { println, ? } = import! std.io + /// let { system_time, duration, ? } = import! std.time + /// + /// let dow = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] + /// do this_moment = lift system_time.now + /// let diff = unwrap_ok_or (duration.from_secs 0) (system_time.duration_since system_time.unix_epoch this_moment) + /// let days = duration.as_secs diff / 60 / 60 / 24 + /// // lift <| println ("It is currently " ++ array.index dow (int.rem (4 + days) 7) ++ " in Greenwich") + /// wrap () + /// ``` now = system_time.now, - - /// Docs + + /// Returns `Ok duration` where `duration` is the amount of time elapsed + /// between the first `SystemTime` and the second `SystemTime`, or `Err duration` + /// if the second `SystemTime` is earlier than the first. (The order of the + /// parameters is flipped relative to the Rust standard library function.) + /// + /// This function may error because measurements taken earlier are not + /// guaranteed to always be before later measurements (due to anomalies such + /// as the system clock being adjusted either forwards or backwards). + /// `Instant` can be used to measure elapsed time without this risk of failure. + /// + /// # Examples + /// + /// ``` + /// let { (<|), (<<) } = import! std.function + /// let { wrap } = import! std.applicative + /// let { Result } = import! std.result + /// let { ? } = import! std.effect + /// let { lift, ? } = import! std.effect.lift + /// let { println, ? } = import! std.io + /// let { system_time, duration, ? } = import! std.time + /// + /// do moment1 = lift system_time.now + /// do moment2 = lift system_time.now + /// // match system_time.duration_since moment1 moment2 with + /// // | Ok dur -> lift <| println <| "moment1 occurred " + /// // ++ (show << duration.as_nanos) dur + /// // ++ " ns before moment2" + /// // | Err dur -> lift <| println <| "moment1 seems to have occurred " + /// // ++ (show << duration.as_nanos) dur + /// // ++ " ns AFTER moment2" + /// wrap () + /// ``` duration_since = system_time.duration_since, - /// Docs + /// Returns the amount of time elapsed between the first system time and the second, + /// or a duration of zero if the second system time is earlier than the first. (The order of the + /// parameters is flipped relative to the Rust standard library function.) + saturating_duration_since = system_time.saturating_duration_since, + + /// Returns `Ok duration` where `duration` is the amount of time elapsed + /// since the given `SystemTime` was created, or `Err duration` if the given + /// `SystemTime` is earlier than the current time. (The order of the + /// parameters is flipped relative to the Rust standard library function.) + /// + /// This function may error because measurements taken earlier are not + /// guaranteed to always be before later measurements (due to anomalies such + /// as the system clock being adjusted either forwards or backwards). + /// `Instant` can be used to measure elapsed time without this risk of failure. + /// + /// # Examples + /// + /// ``` + /// let { (<|), (<<) } = import! std.function + /// let { wrap } = import! std.applicative + /// let { Result } = import! std.result + /// let { ? } = import! std.effect + /// let { lift, ? } = import! std.effect.lift + /// let { println, ? } = import! std.io + /// let { system_time, duration, ? } = import! std.time + /// + /// do moment = lift system_time.now + /// do diff = lift <| system_time.elapsed moment + /// // match diff with + /// // | Ok dur -> lift <| println <| "moment occurred " + /// // ++ (show << duration.as_nanos) dur + /// // ++ " ns ago" + /// // | Err dur -> lift <| println <| "moment apparently will occur in " + /// // ++ (show << duration.as_nanos) dur + /// // ++ " ns" + /// wrap () + /// ``` elapsed = system_time.elapsed, - - /// Docs + + /// Returns `Some t` where `t` is the time `moment + duration` if `t` can be + /// represented as an `SystemTime` (which means it's inside the bounds of the + /// underlying data structure) and `None` otherwise. + /// + /// # Examples + /// + /// ``` + /// let { (<|) } = import! std.function + /// let { assert_some, ? } = import! std.test + /// let { ? } = import! std.effect + /// let { lift, ? } = import! std.effect.lift + /// let { ? } = import! std.io + /// let { system_time, duration, ? } = import! std.time + /// + /// do moment = lift system_time.now + /// assert_some <| system_time.checked_add moment (duration.from_secs 3) + /// ``` checked_add = system_time.checked_add, - /// Docs + /// Returns `Some t` where `t` is the time `moment - duration` if `t` can be + /// represented as an `SystemTime` (which means it's inside the bounds of the + /// underlying data structure) and `None` otherwise. + /// + /// # Examples + /// + /// ``` + /// let { (<|) } = import! std.function + /// let { assert_some, ? } = import! std.test + /// let { ? } = import! std.effect + /// let { lift, ? } = import! std.effect.lift + /// let { ? } = import! std.io + /// let { system_time, duration, ? } = import! std.time + /// + /// do moment = lift system_time.now + /// assert_some <| system_time.checked_sub moment (duration.from_secs 3) + /// ``` checked_sub = system_time.checked_sub, eq, From 2eaaf1d3d796503b2a254e931766aabc52b13be7 Mon Sep 17 00:00:00 2001 From: Etherian Date: Sun, 6 Sep 2020 17:21:16 -0400 Subject: [PATCH 14/16] add saturating_duration_since to instant.glu --- std/time/instant.glu | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/std/time/instant.glu b/std/time/instant.glu index 88e219501e..d7050ad919 100644 --- a/std/time/instant.glu +++ b/std/time/instant.glu @@ -97,9 +97,34 @@ let ord : Ord Instant = /// ``` duration_since = instant.duration_since, - /// Returns the amount of time elapsed since the given `Instant` was created - /// or None if the current time is earlier than the `Instant`, which can - /// happen if an `Instant` is produced synthetically. + /// Returns the amount of time elapsed between the first instant and the second, + /// or a duration of zero if the second instant is earlier than the first. (The order of the + /// parameters is flipped relative to the Rust standard library function.) + /// + /// # Examples + /// + /// ``` + /// let { (<|), const } = import! std.function + /// let { wrap } = import! std.applicative + /// let { assert_eq, assert_gte, assert_success, ? } = import! std.test + /// let { Eff, ? } = import! std.effect + /// let { Error, some_or_throw, ? } = import! std.effect.error + /// let { Lift, lift, ? } = import! std.effect.lift + /// let { instant, duration, ? } = import! std.time + /// + /// let dur_show : Show duration.Duration = { show = const "" } + /// + /// do moment1 = lift instant.now + /// do moment2 = lift instant.now + /// seq assert_gte + /// (instant.saturating_duration_since moment1 moment2) + /// (duration.from_secs 0) + /// assert_eq + /// (instant.saturating_duration_since moment2 moment1) + /// (duration.from_secs 0) + /// ``` + saturating_duration_since = instant.saturating_duration_since, + /// /// # Examples /// From 3e9878214235a34b2c954a81b6d1c00ca2509556 Mon Sep 17 00:00:00 2001 From: Etherian Date: Sun, 6 Sep 2020 17:22:08 -0400 Subject: [PATCH 15/16] clean up doc comments in duration.glu and instant.glu --- std/time/duration.glu | 61 ++++++++++++++++++++------------- std/time/instant.glu | 78 ++++++++++++++++++++++++++++--------------- 2 files changed, 88 insertions(+), 51 deletions(-) diff --git a/std/time/duration.glu b/std/time/duration.glu index ab5361348e..c6507e677e 100644 --- a/std/time/duration.glu +++ b/std/time/duration.glu @@ -1,8 +1,7 @@ //! A `Duration` type for representing and working with spans of time // Documentation in this module is mostly modified from Rust's std::time crate. -let { Ordering } = import! std.types -let { Eq, Ord } = import! std.cmp +let { Eq, Ord, Ordering } = import! std.cmp let { duration } = import! std.time.prim let { Duration } = duration @@ -30,6 +29,8 @@ let ord : Ord Duration = /// # Examples /// /// ``` + /// let { (|>) } = import! std.function + /// let { map } = import! std.functor /// let { ? } = import! std.effect /// let { assert_eq, ? } = import! std.test /// let { duration } = import! std.time @@ -42,7 +43,7 @@ let ord : Ord Duration = /// (duration.checked_add five_seconds five_seconds |> map duration.as_secs) /// ``` Duration, - + /// Creates a new `Duration` from the specified number of whole seconds and /// additional nanoseconds. /// @@ -57,12 +58,16 @@ let ord : Ord Duration = /// # Examples /// /// ``` + /// let { wrap } = import! std.applicative + /// let { ? } = import! std.effect /// let { duration } = import! std.time /// /// let five_and_a_half_seconds = duration.new 5 500000000 + /// let one_tenth_of_a_second = duration.new 0 100000000 + /// wrap () /// ``` new = duration.new, - + /// Creates a new `Duration` from the specified number of whole seconds. /// /// # Panics @@ -74,7 +79,7 @@ let ord : Ord Duration = /// ``` /// let { ? } = import! std.effect /// let { assert_eq, ? } = import! std.test - /// let { duration } = import! std.time + /// let { duration, ? } = import! std.time /// /// let five_seconds = duration.from_secs 5 /// @@ -94,7 +99,7 @@ let ord : Ord Duration = /// ``` /// let { ? } = import! std.effect /// let { assert_eq, ? } = import! std.test - /// let { duration } = import! std.time + /// let { duration, ? } = import! std.time /// /// let two_and_a_half_seconds = duration.from_millis 2500 /// @@ -254,7 +259,7 @@ let ord : Ord Duration = /// /// let dur = duration.new 3 141592653 /// - /// seq assert_eq 3141 (duration.as_millis dur) + /// assert_eq 3141 (duration.as_millis dur) /// ``` as_millis = duration.as_millis, @@ -305,18 +310,20 @@ let ord : Ord Duration = /// /// ``` /// let int = import! std.int + /// let { const } = import! std.function /// let { ? } = import! std.effect - /// let { assert_eq, ? } = import! std.test - /// let { duration } = import! std.time + /// let { assert_eq, assert_none, ? } = import! std.test + /// let { duration, ? } = import! std.time /// /// let dur_x = duration.new 3 500000000 /// let dur_y = duration.new 5 250000000 - /// let dur_max = duration.new int.max_value 250000000 + /// let dur_max = duration.new int.max_value int.max_value + /// + /// let dur_show : Show duration.Duration = { show = const "" } /// /// seq assert_eq (Some (duration.new 8 750000000)) /// (duration.checked_add dur_x dur_y) - /// assert_eq None - /// (duration.checked_add dur_max dur_y) + /// assert_none (duration.checked_add dur_max dur_max) /// ``` checked_add = duration.checked_add, @@ -326,17 +333,19 @@ let ord : Ord Duration = /// # Examples /// /// ``` + /// let { const } = import! std.function /// let { ? } = import! std.effect - /// let { assert_eq, ? } = import! std.test - /// let { duration } = import! std.time + /// let { assert_eq, assert_none, ? } = import! std.test + /// let { duration, ? } = import! std.time + /// + /// let dur_show : Show duration.Duration = { show = const "" } /// /// let dur_small = duration.new 3 500000000 /// let dur_big = duration.new 5 250000000 /// /// seq assert_eq (Some (duration.new 1 750000000)) /// (duration.checked_sub dur_big dur_small) - /// assert_eq None - /// (duration.checked_sub dur_small dur_big) + /// assert_none (duration.checked_sub dur_small dur_big) /// ``` checked_sub = duration.checked_sub, @@ -347,9 +356,12 @@ let ord : Ord Duration = /// /// ``` /// let int = import! std.int + /// let { const } = import! std.function /// let { ? } = import! std.effect - /// let { assert_eq, ? } = import! std.test - /// let { duration } = import! std.time + /// let { assert_eq, assert_none, ? } = import! std.test + /// let { duration, ? } = import! std.time + /// + /// let dur_show : Show duration.Duration = { show = const "" } /// /// let dur = duration.new 3 500000000 /// let dur_max = duration.new int.max_value 250000000 @@ -358,8 +370,7 @@ let ord : Ord Duration = /// (duration.checked_mul dur 5) /// seq assert_eq None /// (duration.checked_mul dur -5) - /// assert_eq None - /// (duration.checked_mul dur_max 5) + /// assert_none (duration.checked_mul dur_max 5) /// ``` checked_mul = duration.checked_mul, @@ -369,16 +380,18 @@ let ord : Ord Duration = /// # Examples /// /// ``` + /// let { const } = import! std.function /// let { ? } = import! std.effect - /// let { assert_eq, ? } = import! std.test - /// let { duration } = import! std.time + /// let { assert_eq, assert_none, ? } = import! std.test + /// let { duration, ? } = import! std.time + /// + /// let dur_show : Show duration.Duration = { show = const "" } /// /// let dur = duration.new 3 500000000 /// /// seq assert_eq (Some (duration.new 1 750000000)) /// (duration.checked_div dur 2) - /// assert_eq None - /// (duration.checked_div dur 0) + /// assert_none (duration.checked_div dur 0) /// ``` checked_div = duration.checked_div, diff --git a/std/time/instant.glu b/std/time/instant.glu index d7050ad919..7fb707ad3c 100644 --- a/std/time/instant.glu +++ b/std/time/instant.glu @@ -1,8 +1,7 @@ //! A measurement on a monotonically-nondecreasing clock. Opaque and useful only with `Duration`. // Documentation in this module is mostly modified from Rust's std::time crate. -let { Ordering } = import! std.types -let { Eq, Ord } = import! std.cmp +let { Eq, Ord, Ordering } = import! std.cmp let { instant } = import! std.time.prim let { Instant } = instant @@ -44,16 +43,23 @@ let ord : Ord Instant = /// Example: /// /// ``` + /// let { (<<), (<|) } = import! std.function + /// let { map } = import! std.functor + /// let { wrap } = import! std.applicative + /// let { unwrap_ok_or } = import! std.result /// let { print, ? } = import! std.io + /// let { ? } = import! std.effect + /// let { Lift, lift, ? } = import! std.effect.lift /// let { assert_eq, ? } = import! std.test - /// let { duration, instant } = import! std.time + /// let { duration, instant, ? } = import! std.time /// /// let long_computation x : [Num a] -> a -> a = x * x /// - /// do start = instant.now - /// let result = long_computation 12 - /// do time_taken = instant.elapsed start - /// print << show << duration.as_nanos time_taken + /// do start = lift instant.now + /// // let x = long_computation 12 + /// // do time_taken = lift <| map (unwrap_ok_or (duration.from_secs 0)) <| instant.elapsed start + /// // lift << print << show <| duration.as_nanos time_taken + /// wrap () /// ``` Instant, @@ -62,37 +68,44 @@ let ord : Ord Instant = /// # Examples /// /// ``` - /// let { wrap } = import! std.applicative + /// let { (<|), const } = import! std.function /// let { ? } = import! std.effect - /// let { assert, ? } = import! std.test - /// let { instant, ? } = import! std.time + /// let { Lift, lift, ? } = import! std.effect.lift + /// let { assert_lte, ? } = import! std.test + /// let { duration, instant, ? } = import! std.time + /// + /// let inst_show : Show instant.Instant = { show = const "" } /// - /// do moment1 = instant.now - /// do moment2 = instant.now - /// wrap (assert (moment1 <= moment2)) + /// do moment1 = lift instant.now + /// do moment2 = lift instant.now + /// assert_lte moment1 moment2 /// ``` now = instant.now, - /// Returns the amount of time elapsed between the first instant and the second, - /// or None if the second instant is earlier than the first. (The order of the + /// Returns `Ok duration` where `duration` is the amount of time elapsed + /// between the first `Instant` and the second `Instant`, or `Err duration` + /// if the second `Instant` is earlier than the first. (The order of the /// parameters is flipped relative to the Rust standard library function.) /// /// # Examples /// /// ``` - /// let { (<|) } = import! std.function + /// let { (<|), const } = import! std.function + /// let { ? } = import! std.unit /// let { wrap } = import! std.applicative - /// let { assert, assert_success, ? } = import! std.test + /// let { Test, assert_gte, assert_success, ? } = import! std.test /// let { Eff, ? } = import! std.effect - /// let { Error, some_or_throw, ? } = import! std.effect.error + /// let { Error, ok_or_throw, ? } = import! std.effect.error /// let { Lift, lift, ? } = import! std.effect.lift /// let { instant, duration, ? } = import! std.time /// - /// let example : Eff [| lift: Lift IO, error: Error () | r |] () = + /// let dur_show : Show duration.Duration = { show = const "" } + /// + /// let example : Eff [| lift: Lift IO, error: Error duration.Duration, writer: Test | r |] () = /// do moment1 = lift instant.now /// do moment2 = lift instant.now - /// do dur = some_or_throw () <| instant.duration_since moment1 moment2 - /// wrap <| assert (dur >= (duration.from_secs 0)) + /// do dur = ok_or_throw <| instant.duration_since moment1 moment2 + /// assert_gte dur (duration.from_secs 0) /// assert_success example /// ``` duration_since = instant.duration_since, @@ -125,24 +138,33 @@ let ord : Ord Instant = /// ``` saturating_duration_since = instant.saturating_duration_since, + /// Returns `Ok duration` where `duration` is the amount of time elapsed + /// since the given `Instant` was created, or `Err duration` if the given + /// `Instant` is later than the current time. (The order of the + /// parameters is flipped relative to the Rust standard library function.) + /// + /// This function may error if the `Instant` was produced synthetically, but + /// should succeed otherwise. /// /// # Examples /// /// ``` /// let { ? } = import! std.unit - /// let { (<|) } = import! std.function + /// let { (<|), const } = import! std.function /// let { wrap } = import! std.applicative /// let { (=<<) } = import! std.monad - /// let { assert, assert_success, ? } = import! std.test + /// let { Test, assert_gte, assert_success, ? } = import! std.test /// let { Eff, ? } = import! std.effect - /// let { Error, some_or_throw, ? } = import! std.effect.error + /// let { Error, ok_or_throw, ? } = import! std.effect.error /// let { Lift, lift, ? } = import! std.effect.lift /// let { ? } = import! std.io /// let { instant, duration, ? } = import! std.time /// - /// let example : Eff [| lift: Lift IO, error: Error () | r |] () = - /// do dur = some_or_throw () =<< lift (instant.elapsed =<< instant.now) - /// wrap <| assert (dur >= (duration.from_secs 0)) + /// let dur_show : Show duration.Duration = { show = const "" } + /// + /// let example : Eff [| lift: Lift IO, error: Error duration.Duration, writer: Test | r |] () = + /// do dur = ok_or_throw =<< lift (instant.elapsed =<< instant.now) + /// assert_gte dur (duration.from_secs 0) /// assert_success example /// ``` elapsed = instant.elapsed, @@ -156,6 +178,7 @@ let ord : Ord Instant = /// ``` /// let { (<|) } = import! std.function /// let { assert_some, ? } = import! std.test + /// let { ? } = import! std.effect /// let { lift, ? } = import! std.effect.lift /// let { ? } = import! std.io /// let { instant, duration, ? } = import! std.time @@ -174,6 +197,7 @@ let ord : Ord Instant = /// ``` /// let { (<|) } = import! std.function /// let { assert_some, ? } = import! std.test + /// let { ? } = import! std.effect /// let { lift, ? } = import! std.effect.lift /// let { ? } = import! std.io /// let { instant, duration, ? } = import! std.time From 996e0cce4cf8ffb4922b285016346be6686748dc Mon Sep 17 00:00:00 2001 From: Etherian Date: Thu, 29 Jul 2021 22:42:01 -0400 Subject: [PATCH 16/16] feat(std.time): expose types in std.time --- std/time.glu | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/std/time.glu b/std/time.glu index c934d7b016..f859e9db00 100644 --- a/std/time.glu +++ b/std/time.glu @@ -1,9 +1,13 @@ //! Time-related functionality -let duration = import! std.time.duration -let instant = import! std.time.instant -let system_time = import! std.time.system_time +let duration @ { Duration } = import! std.time.duration +let instant @ { Instant } = import! std.time.instant +let system_time @ { SystemTime } = import! std.time.system_time { + Duration, + Instant, + SystemTime, + duration, instant, system_time,