go.mway.dev/chrono@v0.6.1-0.20240126030049-189c5aef20d2/clock/clock.go (about) 1 // Copyright (c) 2023 Matt Way 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to 5 // deal in the Software without restriction, including without limitation the 6 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 // sell copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 // IN THE THE SOFTWARE. 20 21 // Package clock provides clock-related types and utilities. 22 package clock 23 24 import ( 25 "errors" 26 "time" 27 ) 28 29 // ErrNoClockFunc is returned when creating a new [Clock] without a valid 30 // [TimeFunc] or [NanotimeFunc]. 31 var ErrNoClockFunc = errors.New("no clock function provided") 32 33 // A Clock tells time. 34 type Clock interface { 35 // After waits for the duration to elapse and then sends the current time 36 // on the returned channel. It is equivalent to NewTimer(d).C. The 37 // underlying [Timer] is not recovered by the garbage collector until the 38 // it fires. If efficiency is a concern, use [NewTimer] instead and call 39 // [Timer.Stop] if the timer is no longer needed. 40 After(d time.Duration) <-chan time.Time 41 42 // AfterFunc waits for the duration to elapse and then calls fn in its own 43 // goroutine. It returns a [Timer] that can be used to cancel the call using 44 // its [Timer.Stop] method. 45 AfterFunc(d time.Duration, fn func()) *Timer 46 47 // Nanotime returns the current time in nanoseconds. 48 Nanotime() int64 49 50 // NewStopwatch returns a new [Stopwatch] that uses the [Clock] for 51 // measuring time. 52 NewStopwatch() *Stopwatch 53 54 // NewTicker returns a new [Ticker] containing a channel that will send the 55 // current time on the channel after each tick. The period of the ticks is 56 // specified by the duration argument. The ticker will adjust the time 57 // interval or drop ticks to make up for slow receivers. The duration d 58 // must be greater than zero; if not, NewTicker will panic. Stop the ticker 59 // to release associated resources. 60 NewTicker(d time.Duration) *Ticker 61 62 // NewTimer creates a new [Timer] that will send the current time on its 63 // channel after at least d has elapsed. 64 NewTimer(d time.Duration) *Timer 65 66 // Now returns the current time. For wall clocks, this is the local time; 67 // for monotonic clocks, this is the system's monotonic time. Other Clock 68 // implementations may have different locale or clock time semantics. 69 Now() time.Time 70 71 // Since returns the time elapsed since t. It is shorthand for 72 // Now().Sub(t). 73 Since(t time.Time) time.Duration 74 75 // Since returns the time elapsed since ns. It is shorthand for 76 // Nanotime()-ns. 77 SinceNanotime(ns int64) time.Duration 78 79 // Sleep pauses the current goroutine for at least the duration d. A 80 // negative or zero duration causes Sleep to return immediately. 81 Sleep(d time.Duration) 82 83 // Tick is a convenience wrapper for [NewTicker] providing access to the 84 // ticking channel only. While Tick is useful for clients that have no need 85 // to shut down the [Ticker], be aware that without a way to shut it down 86 // the underlying Ticker cannot be recovered by the garbage collector; it 87 // "leaks". Like [NewTicker], Tick will panic if d <= 0. 88 Tick(time.Duration) <-chan time.Time 89 } 90 91 // NewClock returns a new [Clock] based on the given options. 92 func NewClock(opts ...Option) (Clock, error) { 93 options := DefaultOptions() 94 for _, opt := range opts { 95 opt.apply(&options) 96 } 97 98 if options.NanotimeFunc != nil { 99 return newMonotonicClock(options.NanotimeFunc), nil 100 } 101 102 return newWallClock(options.TimeFunc), nil 103 } 104 105 // MustClock panics if the given error is not nil, otherwise it returns the 106 // given [Clock]. 107 func MustClock(clock Clock, err error) Clock { 108 if err != nil { 109 panic(err) 110 } 111 112 return clock 113 } 114 115 // NewMonotonicClock returns a new monotonic [Clock]. 116 func NewMonotonicClock() Clock { 117 return MustClock(NewClock(WithNanotimeFunc(DefaultNanotimeFunc()))) 118 } 119 120 // NewWallClock returns a new wall [Clock]. 121 func NewWallClock() Clock { 122 return MustClock(NewClock(WithTimeFunc(DefaultTimeFunc()))) 123 }