package neo
import (
"sort"
"sync"
"time"
)
type Timer interface {
C () <-chan time .Time
Stop () bool
Reset (d time .Duration )
}
type Ticker interface {
C () <-chan time .Time
Stop ()
Reset (d time .Duration )
}
func NewTime (now time .Time ) *Time {
return &Time {
now : now ,
moments : map [int ]moment {},
}
}
type Time struct {
mux sync .Mutex
now time .Time
momentID int
moments map [int ]moment
observers []chan struct {}
}
func (t *Time ) Timer (d time .Duration ) Timer {
tt := &timer {
time : t ,
ch : make (chan time .Time , 1 ),
}
tt .id = t .plan (t .When (d ), tt .do )
return tt
}
func (t *Time ) Ticker (d time .Duration ) Ticker {
tt := &ticker {
time : t ,
ch : make (chan time .Time , 1 ),
dur : d ,
}
tt .id = t .plan (t .When (d ), tt .do )
return tt
}
func (t *Time ) planUnlocked (when time .Time , do func (now time .Time )) int {
id := t .momentID
t .momentID ++
t .moments [id ] = moment {
when : when ,
do : do ,
}
t .observeUnlocked ()
return id
}
func (t *Time ) plan (when time .Time , do func (now time .Time )) int {
t .mux .Lock ()
defer t .mux .Unlock ()
return t .planUnlocked (when , do )
}
func (t *Time ) stop (id int ) bool {
t .mux .Lock ()
defer t .mux .Unlock ()
_ , ok := t .moments [id ]
delete (t .moments , id )
return ok
}
func (t *Time ) reset (d time .Duration , id int , do func (now time .Time ), durp *time .Duration ) {
t .mux .Lock ()
defer t .mux .Unlock ()
t .resetUnlocked (d , id , do , durp )
}
func (t *Time ) resetUnlocked (d time .Duration , id int , do func (now time .Time ), durp *time .Duration ) {
if durp != nil {
*durp = d
}
m , ok := t .moments [id ]
if !ok {
m = moment {do : do }
}
m .when = t .now .Add (d )
t .moments [id ] = m
}
func (t *Time ) tickUnlocked () moments {
var past moments
for id , m := range t .moments {
if m .when .After (t .now ) {
continue
}
delete (t .moments , id )
past = append (past , m )
}
sort .Sort (past )
return past
}
func (t *Time ) Now () time .Time {
t .mux .Lock ()
defer t .mux .Unlock ()
return t .now
}
func (t *Time ) Set (now time .Time ) {
t .mux .Lock ()
defer t .mux .Unlock ()
t .setUnlocked (now )
}
func (t *Time ) Travel (d time .Duration ) time .Time {
t .mux .Lock ()
defer t .mux .Unlock ()
now := t .now .Add (d )
t .setUnlocked (now )
return now
}
func (t *Time ) TravelDate (years , months , days int ) time .Time {
t .mux .Lock ()
defer t .mux .Unlock ()
now := t .now .AddDate (years , months , days )
t .setUnlocked (now )
return now
}
func (t *Time ) setUnlocked (now time .Time ) {
t .now = now
t .tickUnlocked ().do (now )
}
func (t *Time ) Sleep (d time .Duration ) { <-t .After (d ) }
func (t *Time ) When (d time .Duration ) time .Time {
return t .Now ().Add (d )
}
func (t *Time ) After (d time .Duration ) <-chan time .Time {
done := make (chan time .Time , 1 )
t .plan (t .When (d ), func (now time .Time ) {
done <- now
})
return done
}
func (t *Time ) Observe () <-chan struct {} {
observer := make (chan struct {})
t .mux .Lock ()
t .observers = append (t .observers , observer )
t .mux .Unlock ()
return observer
}
func (t *Time ) observeUnlocked () {
for _ , observer := range t .observers {
close (observer )
}
t .observers = t .observers [:0 ]
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .