From 5f6fca29866406b305687ce5788fca77a2b1c38d Mon Sep 17 00:00:00 2001 From: DEV Date: Wed, 21 Feb 2024 00:55:52 +0100 Subject: [PATCH] scopes --- core/syncs/tasks/completer.go | 42 +++ core/syncs/tasks/completion.go | 301 ++++++++++++++++++++ core/syncs/tasks/completion_context.go | 39 +++ core/syncs/tasks/completion_mode.go | 90 ++++++ core/syncs/tasks/completion_ops.go | 91 ++++++ core/syncs/tasks/completion_result.go | 51 ++++ core/syncs/tasks/completion_result_error.go | 73 +++++ core/syncs/tasks/completion_result_kind.go | 83 ++++++ core/syncs/tasks/completion_result_list.go | 87 ++++++ core/syncs/tasks/completion_result_value.go | 73 +++++ core/syncs/tasks/completion_result_void.go | 69 +++++ core/syncs/tasks/completion_state.go | 58 ++++ core/syncs/tasks/gogo.go | 44 +++ core/syncs/tasks/worker_pool.go | 145 +++++++++- core/{times => timers}/chrono.go | 2 +- core/{times => timers}/chronometer.go | 2 +- core/{times => timers}/expiration.go | 2 +- core/{times => timers}/expiration_source.go | 2 +- core/{times => timers}/expirer.go | 2 +- core/timers/go.mod | 4 + core/timers/gogo.go | 71 +++++ core/{times => timers}/pulsar.go | 2 +- core/{times => timers}/time_task.go | 2 +- core/{times => timers}/timer_queue.go | 2 +- core/{times => timers}/timer_state.go | 2 +- core/{times => timers}/timer_task.go | 2 +- core/{times => timers}/timer_task_heap.go | 2 +- core/times/bdates/bmonth.go | 33 +++ core/times/bdates/bweek.go | 125 ++++++++ core/times/bdates/byear.go | 31 ++ core/times/date_days.go | 102 +++++++ core/times/date_days_range.go | 92 ++++++ core/times/duration_formatter.go | 7 +- core/times/go.mod | 3 +- core/times/gogo.go | 68 ++--- core/times/time_formatter.go | 18 +- go.work | 1 + 37 files changed, 1759 insertions(+), 64 deletions(-) create mode 100644 core/syncs/tasks/completer.go create mode 100644 core/syncs/tasks/completion.go create mode 100644 core/syncs/tasks/completion_context.go create mode 100644 core/syncs/tasks/completion_mode.go create mode 100644 core/syncs/tasks/completion_ops.go create mode 100644 core/syncs/tasks/completion_result.go create mode 100644 core/syncs/tasks/completion_result_error.go create mode 100644 core/syncs/tasks/completion_result_kind.go create mode 100644 core/syncs/tasks/completion_result_list.go create mode 100644 core/syncs/tasks/completion_result_value.go create mode 100644 core/syncs/tasks/completion_result_void.go create mode 100644 core/syncs/tasks/completion_state.go rename core/{times => timers}/chrono.go (99%) rename core/{times => timers}/chronometer.go (98%) rename core/{times => timers}/expiration.go (99%) rename core/{times => timers}/expiration_source.go (99%) rename core/{times => timers}/expirer.go (98%) create mode 100644 core/timers/go.mod create mode 100644 core/timers/gogo.go rename core/{times => timers}/pulsar.go (99%) rename core/{times => timers}/time_task.go (98%) rename core/{times => timers}/timer_queue.go (99%) rename core/{times => timers}/timer_state.go (99%) rename core/{times => timers}/timer_task.go (99%) rename core/{times => timers}/timer_task_heap.go (99%) create mode 100644 core/times/bdates/bmonth.go create mode 100644 core/times/bdates/bweek.go create mode 100644 core/times/bdates/byear.go create mode 100644 core/times/date_days.go create mode 100644 core/times/date_days_range.go diff --git a/core/syncs/tasks/completer.go b/core/syncs/tasks/completer.go new file mode 100644 index 0000000..873c9c0 --- /dev/null +++ b/core/syncs/tasks/completer.go @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completer.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + +type ( + + Completer interface { + + Complete (context CompletionContext, cid int) + } + + + CompleteFnc func (context CompletionContext, cid int) + +) + + + +func (f CompleteFnc) Complete (context CompletionContext, cid int) { + f(context,cid) } diff --git a/core/syncs/tasks/completion.go b/core/syncs/tasks/completion.go new file mode 100644 index 0000000..3ac3a17 --- /dev/null +++ b/core/syncs/tasks/completion.go @@ -0,0 +1,301 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + +import ( + "activething.com/go/gogo/core/opts" + "activething.com/go/gogo/core/timers" + "context" + "sync" + "sync/atomic" +) + +type ( + + Completion struct { + /*embedded*/context.Context + mux sync.RWMutex + wgr sync.WaitGroup + + parent CompletionContext + expiration *timers.Expiration + + mode CompletionMode + state uint32 + pending uint32 + + cid int + result CompletionResult + + dispatchFn dispatchFnc + cancelFn func() + + completers []Completer + } + + + dispatchFnc func (*Completion, Completer, int) error + + +) + + +func NewCompletion (options ...opts.OptionErrFnc[Completion]) (*Completion,error) { + c,e := opts.ApplyAndCheck[Completion](&Completion { + mode : CompletionModeAll, + cid : CompletionFromSelf, + dispatchFn: dispatcher, + },options...) + if e != nil { + return nil,e + } + if c.expiration == nil { + c.expiration = timers.NewExpiration(0,nil) + } + return c,nil +} + + +func (c *Completion) Mode () CompletionMode { + return c.mode } + +func (c *Completion) State () CompletionState { + return CompletionState(atomic.LoadUint32(&c.state)) } + +func (c *Completion) Pending() int { + return int(atomic.LoadUint32(&c.pending)) } + +func (c *Completion) IsCompleted () bool { + return c.State() > CompletionStateStarted } + +func (c *Completion) Chrono () timers.Chronometer { + return c.expiration.Chono() } + +func (c *Completion) Result () CompletionResult { + c.wgr.Wait() + return c.result +} + +func (c *Completion) Wait () { + c.wgr.Wait() } + + +func (c *Completion) AddCompleter (cms ... Completer) error { + c.mux.Lock() + if c.State() != CompletionStateCreated { + c.mux.Unlock() + return G.ErrInvalidState + } + for _,cm := range cms { + c.completers = append(c.completers, cm) + } + c.mux.Unlock() + return nil +} + + +func (c *Completion) Cancel () { + c.notify(CompletionFromRequest,CompletionStateCanceled,nil,G.ErrCancelByRequest) } + + +func (c *Completion) Start (ctx context.Context) error { + return c.complete(ctx,nil,CompletionFromSelf) } + + +func (c *Completion) Complete (cmp CompletionContext, cid int) { + _ = c.complete(nil,cmp,cid) } + + + +func (c *Completion) complete (ctx context.Context, cctx CompletionContext, cid int) error { + c.mux.Lock() + + if c.State() != CompletionStateCreated { + c.mux.Unlock() + return G.ErrInvalidState + } + + // Nos sirve para determinar de donde va a depender la expiracion + // en tiempo de la completion en caso de que exista, o bien de la + // completion padre o bien del contexto. + // + var ex timers.Expirer + + if cctx != nil { + c.parent = cctx + c.Context= cctx + c.cid = cid + if c.parent.IsCompleted() { + c.mux.Unlock() + c.notify(CompletionFromParent,CompletionStateCanceled,nil,G.ErrCancelByParent) + return G.ErrCancelByParent + } + ex = c.parent + } else { + if ctx == nil { + c.Context = context.Background() + } else { + c.Context = ctx + if ctx.Err() != nil { + c.mux.Unlock() + c.notify(CompletionFromContext,CompletionStateCanceled,nil,G.ErrCancelByContext) + return G.ErrCancelByContext.WithCause(ctx.Err()) + } + + ch := make(chan struct{}) + c.cancelFn = func(){ close(ch)} + go func(cc *Completion, ch chan struct{}){ + select { + case <- ch: + case <- cc.Context.Done() : + er := G.ErrCancelByContext.WithCause(cc.Context.Err()) + cc.notify(CompletionFromContext,CompletionStateCanceled,nil,er) + } + }(c,ch) + } + ex = ctx + } + + if er := c.expiration.Start(ex); er != nil { + c.mux.Unlock() + c.notify(CompletionFromSelf,CompletionStateFaulted,nil,er) + return er + } + + atomic.StoreUint32(&c.state,uint32(CompletionStateStarted)) + c.wgr.Add(1) + + go func (c *Completion) { + ln := len(c.completers) + if ln == 0 { + c.mux.Unlock() + c.notify(CompletionFromSelf, CompletionStateCompleted, nil, nil) + return + } + + atomic.StoreUint32(&c.pending,uint32(ln)) + cs := c.completers + c.mux.Unlock() + + for ix, cm := range cs { + if c.IsCompleted() { + return + } + if er := c.dispatchFn(c,cm,ix); er != nil { + c.notify(CompletionFromSelf,CompletionStateFaulted,nil,er) + return + } + } + }(c) + + return nil +} + + + +func (c *Completion) Notify (frm int, val interface{}, err error) { + c.notify(frm,CompletionStateCompleted,val,err) } + + + +func (c *Completion) notify (frm int, ste CompletionState, val interface{}, err error) { + c.mux.Lock() + os := c.State() + if os > CompletionStateStarted { + c.mux.Unlock() + return + } + + if frm >= CompletionFromChild { + cn := atomic.AddUint32(&c.pending,-1) + + switch { + case c.mode.IsAnyOrResult() && val != nil: + atomic.StoreUint32(&c.state,uint32(CompletionStateCompleted)) + c.result = NewCompletionResultValue(frm, val) + + case c.mode.IsAnyOrError() && err != nil: + atomic.StoreUint32(&c.state,uint32(CompletionStateFaulted)) + c.result = NewCompletionResultError(frm, err) + + case c.mode == completionModeTask: + c.result = NewCompletionResult(frm, val, err) + + default: + if c.mode == CompletionModeAll { + if c.result == nil { + c.result = NewCompletionResultList(c.cid, NewCompletionResult(frm, val, err)) + } else { + c.result.(*CompletionResultList).Add(NewCompletionResult(frm, val, err)) + } + } + if cn == 0 { + atomic.StoreUint32(&c.state,uint32(CompletionStateCompleted)) + } else { + c.mux.Unlock() + return + } + } + + } else { + atomic.StoreUint32(&c.state,uint32(ste)) + c.result = NewCompletionResult(frm,val,err) + } + + _ = c.expiration.Stop() + if c.cancelFn != nil { + c.cancelFn() + } + c.wgr.Done() + c.mux.Unlock() + + + // Solo notificamos a las completions hijas y al padre en caso de que se haya iniciado + if os == CompletionStateStarted { + for _, ch := range c.completers { + // Notificamos solo a los completer que a su vez implementan + // CompletionContext + if cm, is := ch.(CompletionContext); is { + if !cm.IsCompleted() { + cm.Notify(CompletionFromParent, nil, G.ErrCancelByParent) + } + } + } + // Notificamos al padre en caso de que tenga y la completion no venga de el + if frm != CompletionFromParent && c.parent != nil { + c.parent.Notify(c.cid,c.result.Value(),c.result.Error()) + } + } +} + + + + + + + +func dispatcher (completion *Completion, completer Completer, cid int) error { + go completer.Complete(completion,cid) + return nil +} \ No newline at end of file diff --git a/core/syncs/tasks/completion_context.go b/core/syncs/tasks/completion_context.go new file mode 100644 index 0000000..d7cbeef --- /dev/null +++ b/core/syncs/tasks/completion_context.go @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_context.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + +import "context" + +type ( + + CompletionContext interface { + context.Context + + IsCompleted () bool + + Notify (cid int, val interface {}, err error) + } +) + + diff --git a/core/syncs/tasks/completion_mode.go b/core/syncs/tasks/completion_mode.go new file mode 100644 index 0000000..ba1502f --- /dev/null +++ b/core/syncs/tasks/completion_mode.go @@ -0,0 +1,90 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_mode.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + +const( + + CompletionModeAll CompletionMode = iota + + // CompletionModeAny Las tareas se ejecutaran haste que se + //produzca el primer resultado o el primer error + CompletionModeAny + + //CompletionModeResult Las tareas se ejecutaran hasta que + //se obtenga el primer resultado. + CompletionModeResult + + //CompletionModeError Las tareas se completaran en el momento de + //que se produzca un error. + CompletionModeError + + //CompletionModeTask Modo para las completions de una sola task + completionModeTask + +) + + +type ( + + CompletionMode uint8 + +) + + +func (m CompletionMode) IsAnyOrResult () bool { + return m == CompletionModeResult || m == CompletionModeAny } + + +func (m CompletionMode) IsAnyOrError () bool { + return m == CompletionModeError || m == CompletionModeAny } + + + +func (m CompletionMode) String () string { + switch m { + case CompletionModeAll : return "all" + case CompletionModeAny : return "any" + case CompletionModeResult: return "result" + case CompletionModeError : return "error" + case completionModeTask : return "task" + default: + return "??" + } +} + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/syncs/tasks/completion_ops.go b/core/syncs/tasks/completion_ops.go new file mode 100644 index 0000000..93a077d --- /dev/null +++ b/core/syncs/tasks/completion_ops.go @@ -0,0 +1,91 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_ops.go +// Created by DEV +// Modified 21/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + +import ( + "activething.com/go/gogo/core/opts" + "activething.com/go/gogog/core/timers" + "time" +) + + +// CompletionWithMode +// Desc: Función para el constructor de Completion, +// establece el mode de como se llegara a la completion +// +func CompletionWithMode (mode CompletionMode) opts.OptionErrFnc[Completion] { + return func(c *Completion) error { + c.mode = mode + return nil + } +} + + +// CompletionWithTimeout +// Desc: Función para el constructor de Completion +// Establece el tiempo máximo de la completion +// +func CompletionWithTimeout (tmo time.Duration) opts.OptionErrFnc[Completion] { + return func(c *Completion) error { + c.expiration = timers.NewExpiration(tmo,func(){ + c.notify(CompletionFromTimer,CompletionStateCanceled,nil,G.ErrCancelByTimer) + }) + return nil + } +} + + +// CompletionWithCompleters +// Desc: Función para el constructor de Completion, +// añade los objeto a completar en la completion +// +func CompletionWithCompleters (completers ... Completer) opts.OptionErrFnc[Completion] { + return func(c *Completion) error { + if c.State() != CompletionStateCreated { + return G.ErrInvalidState + } + for _, cm := range completers { + c.completers = append(c.completers, cm) + } + return nil + } +} + + +// CompletionWithWorkPool +// Desc: Función para el constructor de Completion, +// utiliza un pool de trabajo para completar +// las tareas. +// +func CompletionWithWorkPool (pool *WorkerPool) opts.OptionErrFnc[Completion] { + return func(c *Completion) error { + c.dispatchFn = dispatchFnc(func (cm *Completion, cr Completer, ci int) error { + return pool.DoWork(c,func(){ + cr.Complete(cm,ci) + }) + }) + return nil + } +} + diff --git a/core/syncs/tasks/completion_result.go b/core/syncs/tasks/completion_result.go new file mode 100644 index 0000000..6df152f --- /dev/null +++ b/core/syncs/tasks/completion_result.go @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_result.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + +type ( + + CompletionResult interface { + + CID () int + + Value() any + + Error() error + + Kind () CompletionResultKind + } +) + + +func NewCompletionResult (cid int, val any, err error) CompletionResult { + if err != nil { + return *NewCompletionResultError(cid,err) + } + if val != nil { + return *NewCompletionResultValue(cid,val) + } + return CompletionResultVoid(cid) +} \ No newline at end of file diff --git a/core/syncs/tasks/completion_result_error.go b/core/syncs/tasks/completion_result_error.go new file mode 100644 index 0000000..000b467 --- /dev/null +++ b/core/syncs/tasks/completion_result_error.go @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_result_error.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + + +type ( + + + CompletionResultError struct { + cid int + err error + } + +) + +func NewCompletionResultError (cid int, err error) *CompletionResultError { + return &CompletionResultError{ + cid : cid, + err : err, + } +} + +func (r CompletionResultError) CID () int { + return r.cid } + +func (_ CompletionResultError) Kind () CompletionResultKind { + return CompletionResultKindError } + +func (_ CompletionResultError) Value () any { + return nil } + +func (r CompletionResultError) Error () error { + return r.err } + + + + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/syncs/tasks/completion_result_kind.go b/core/syncs/tasks/completion_result_kind.go new file mode 100644 index 0000000..37ef56d --- /dev/null +++ b/core/syncs/tasks/completion_result_kind.go @@ -0,0 +1,83 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_result_kind.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + + +const( + + CompletionResultKindVoid CompletionResultKind = iota + CompletionResultKindError + CompletionResultKindValue + CompletionResultKindList + +) + + +type ( + + CompletionResultKind uint8 + +) + +func (k CompletionResultKind) IsVoid () bool { + return k == CompletionResultKindVoid } + +func (k CompletionResultKind) IsError() bool { + return k == CompletionResultKindError} + + +func (k CompletionResultKind) IsValue() bool { + return k == CompletionResultKindValue} + + +func (k CompletionResultKind) IsList () bool { + return k == CompletionResultKindList } + + +func (k CompletionResultKind) String () string { + switch k { + case CompletionResultKindVoid : return "void" + case CompletionResultKindValue: return "value" + case CompletionResultKindError: return "error" + case CompletionResultKindList : return "list" + default: + return "??" + } +} + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/syncs/tasks/completion_result_list.go b/core/syncs/tasks/completion_result_list.go new file mode 100644 index 0000000..c531ae3 --- /dev/null +++ b/core/syncs/tasks/completion_result_list.go @@ -0,0 +1,87 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_result_list.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + + +type ( + + + CompletionResultList struct { + cid int + results []CompletionResult + } + +) + +func NewCompletionResultList (cid int, results ... CompletionResult) *CompletionResultList { + ls := make([]CompletionResult,len(results)) + copy(ls, results) + return &CompletionResultList{ + cid: cid, + results: ls, + } +} + + +func (r *CompletionResultList) Add (rsl CompletionResult) { + if rsl != nil { + r.results = append(r.results, rsl) + } +} + + +func (r CompletionResultList) CID () int { + return r.cid } + + +func (_ CompletionResultList) Kind () CompletionResultKind { + return CompletionResultKindList } + + +func (_ CompletionResultList) Error () error { + return nil } + + +func (r CompletionResultList) Value () any { + return r.results } + + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ + + + diff --git a/core/syncs/tasks/completion_result_value.go b/core/syncs/tasks/completion_result_value.go new file mode 100644 index 0000000..3bd8161 --- /dev/null +++ b/core/syncs/tasks/completion_result_value.go @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_result_value.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + + + +type ( + + + CompletionResultValue struct { + cid int + value any + } + +) + +func NewCompletionResultValue (cid int, value any) *CompletionResultValue { + return &CompletionResultValue{ + cid : cid, + value: value, + } +} + +func (r CompletionResultValue) CID () int { + return r.cid } + +func (_ CompletionResultValue) Kind () CompletionResultKind { + return CompletionResultKindValue } + +func (_ CompletionResultValue) Error () error { + return nil } + +func (r CompletionResultValue) Value () any { + return r.value } + + + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/syncs/tasks/completion_result_void.go b/core/syncs/tasks/completion_result_void.go new file mode 100644 index 0000000..13c8b7e --- /dev/null +++ b/core/syncs/tasks/completion_result_void.go @@ -0,0 +1,69 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_result_void.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + + + +type ( + + + CompletionResultVoid int + + +) + + +func (r CompletionResultVoid) CID () int { + return int(r) +} + +func (_ CompletionResultVoid) Kind () CompletionResultKind { + return CompletionResultKindVoid } + +func (_ CompletionResultVoid) Value () any { + return nil } + +func (_ CompletionResultVoid) Error () error { + return nil } + + + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ + + + diff --git a/core/syncs/tasks/completion_state.go b/core/syncs/tasks/completion_state.go new file mode 100644 index 0000000..8b223a5 --- /dev/null +++ b/core/syncs/tasks/completion_state.go @@ -0,0 +1,58 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name completion_state.go +// Created by DEV +// Modified 20/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package tasks + + + +const ( + + CompletionStateCreated CompletionState = iota + CompletionStateStarted + CompletionStateCompleted + CompletionStateCanceled + CompletionStateFaulted + +) + + +type ( + + CompletionState uint32 + +) + + +func (s CompletionState) String () string { + switch s { + case CompletionStateCreated : return "created" + case CompletionStateStarted : return "started" + case CompletionStateCompleted: return "completed" + case CompletionStateCanceled : return "canceled" + case CompletionStateFaulted : return "faulted" + default: return "??" + } +} + + + diff --git a/core/syncs/tasks/gogo.go b/core/syncs/tasks/gogo.go index cb3a20a..8aa92cc 100644 --- a/core/syncs/tasks/gogo.go +++ b/core/syncs/tasks/gogo.go @@ -23,4 +23,48 @@ package tasks +import "activething.com/go/gogo/core/errs" + + + +const ( + + CompletionFromChild int = 0 + CompletionFromSelf int = -1 + CompletionFromParent int = -2 + CompletionFromContext int = -3 + CompletionFromTimer int = -4 + CompletionFromRequest int = -5 + +) + + +var ( + + G = struct { + + ErrInvalidCompletion errs.ErrCode + ErrInvalidState errs.ErrCode + ErrCancelByParent errs.ErrCode + ErrCancelByRequest errs.ErrCode + ErrCancelByContext errs.ErrCode + ErrCancelByTimer errs.ErrCode + + ErrPoolStarted errs.ErrCode + ErrPoolStopped errs.ErrCode + ErrPoolAcquire errs.ErrCode + }{ + ErrInvalidCompletion: errs.ErrCode("syncs:tasks.invalid-completion"), + ErrInvalidState : errs.ErrCode("syncs:tasks.invalid-state"), + ErrCancelByParent : errs.ErrCode("syncs:tasks.cancel-by-parent"), + ErrCancelByRequest : errs.ErrCode("syncs:tasks.cancel-by-request"), + ErrCancelByContext : errs.ErrCode("syncs:tasks.cancel-by-context"), + ErrCancelByTimer : errs.ErrCode("syncs:tasks.cancel-by-timer"), + + ErrPoolStarted : errs.ErrCode("syncs:tasks.pool-started"), + ErrPoolStopped : errs.ErrCode("syncs:tasks.pool-stopped"), + ErrPoolAcquire : errs.ErrCode("syncs:tasks.pool-acquire"), + } +) + diff --git a/core/syncs/tasks/worker_pool.go b/core/syncs/tasks/worker_pool.go index 53b0f10..7bf355a 100644 --- a/core/syncs/tasks/worker_pool.go +++ b/core/syncs/tasks/worker_pool.go @@ -26,6 +26,7 @@ package tasks import ( "activething.com/go/gogo/core/opts" "activething.com/go/gogo/core/syncs" + "context" "runtime" "sync" "sync/atomic" @@ -91,8 +92,7 @@ func (p *WorkerPool) Stats () syncs.PoolStats { func (p *WorkerPool) State () WorkerPoolState { - return WorkerPoolState(atomic.LoadUint32(&p.state)) -} + return WorkerPoolState(atomic.LoadUint32(&p.state)) } func (p *WorkerPool) Count () int32 { return atomic.LoadInt32(&p.count) } @@ -141,11 +141,148 @@ func (p *WorkerPool) Done () <- chan struct{} { func (p *WorkerPool) Start () error { p.mux.Lock() - st := WorkerPoolState(atomic.LoadUint32(&p.state)) + + st := p.State() if st == WorkerPoolStateRunning { p.mux.Unlock() - return + return G.ErrPoolStarted } + + if st == WorkerPoolStateStopped { + atomic.StoreInt32(&p.count,0) + } + + p.doneCh = make(chan struct{}) + p.mux.Unlock() + + go func(p *WorkerPool) { + atomic.StoreUint32(&p.state,uint32(WorkerPoolStateRunning)) + var ls []*worker + for { + p.clearWorkers(&ls) + select { + case <- p.doneCh: + return + default: + time.Sleep(time.Duration(atomic.LoadInt64(&p.maxIdle))) + } + } + }(p) + + return nil } +func (p *WorkerPool) Stop () error { + p.mux.Lock() + if p.State() != WorkerPoolStateRunning { + p.mux.Unlock() + return G.ErrPoolStopped + } + atomic.StoreUint32(&p.state,uint32(WorkerPoolStateStopped)) + + close(p.doneCh) + p.doneCh = nil + ws := p.workers + + for ix,wk := range ws { + wk.jobCh <- nil + ws[ix]=nil + } + + p.workers = ws[:0] + + p.mux.Unlock() + return nil +} + + +func (p *WorkerPool) DoWork(ctx context.Context, job func()) error { + p.mux.Lock() + if p.State() != WorkerPoolStateRunning { + p.mux.Unlock() + return G.ErrPoolStopped + } + + wk := (*worker)(nil) + ws := p.workers + ln := len(ws) - 1 + + if ln >= 0 { + wk = ws[ln] + ws[ln] = nil + p.workers = ws[:ln] + p.mux.Unlock() + } else { + p.mux.Unlock() + + if atomic.LoadInt32(&p.count) >= atomic.LoadInt32(&p.max) { + return G.ErrPoolAcquire + } + atomic.AddInt32(&p.count,1) + wk = p.pool.Get().(*worker) + + go func(p *WorkerPool, w *worker, x context.Context) { + + for job := range w.jobCh { + if job == nil { + break + } + job() + job = nil + + p.mux.Lock() + done := false + if p.State() != WorkerPoolStateStopped { + w.lastTime = time.Now() + p.workers = append(p.workers, w) + done = true + p.stats.AddReleased() + } + p.mux.Unlock() + if !done { + break + } + } + atomic.AddInt32(&p.count,-1) + p.pool.Put(w) + + }(p,wk,ctx) + + } + + p.stats.AddAcquired() + wk.jobCh <- job + return nil +} + + + + +func (p *WorkerPool) clearWorkers (cls *[]*worker) { + p.mux.Lock() + tm := time.Now() + mi := time.Duration(atomic.LoadInt64(&p.maxIdle)) + ws := p.workers + ln := len(ws) + ix := 0 + + for ix mi { + ix++ + } + *cls = append((*cls)[:0],ws[:ix]...) + if ix > 0 { + nt := copy(ws,ws[ix:]) + for ix:= nt; ix 7 { + return w + } + if val { + w |= 1 << num-1 + } else { + w &^= 1 << num-1 + } + return w +} + + +func (w BWeekDays) GetDay (num int) bool { + if num < 0 || num > 7 { + return false + } + c := BWeekDays(1 << num-1) + return (w&c)==c +} + + +func (w BWeekDays) Invert () BWeekDays { + return ^w } + + +func (w BWeekDays) Count () int { + return bits.OnesCount8(uint8(w)) } + + +func (w BWeekDays) List () []int { + c := BWeekDays(1) + r := make([]int,0,7) + for i:=1; i<=7; i++ { + if c&w == c { + r = append(r,i) + } + c <<=1 + } + return r +} + + +func (w BWeekDays) ToSlice () []bool { + c := BWeekDays(1) + r := make([]bool,7) + for i:=0; i<7; i++ { + r[i]=c&w == c + c <<=1 + } + return r +} + + + +func (w BWeekDays) Common (dst BWeekDays) BWeekDays { return w & dst } diff --git a/core/times/bdates/byear.go b/core/times/bdates/byear.go new file mode 100644 index 0000000..99cfd75 --- /dev/null +++ b/core/times/bdates/byear.go @@ -0,0 +1,31 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name byear.go +// Created by DEV +// Modified 21/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package bdates + + +type ( + + BYear [12]BMonth + +) \ No newline at end of file diff --git a/core/times/date_days.go b/core/times/date_days.go new file mode 100644 index 0000000..70e1931 --- /dev/null +++ b/core/times/date_days.go @@ -0,0 +1,102 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name days.go +// Created by DEV +// Modified 21/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package times + +import "time" + + +type ( + + DateDays int32 + +) + + + + +func (d DateDays) AddDate(years, months, days int) DateDays { + return TimeToDays(d.ToTime().AddDate(years,months,days)) } + + +func (d DateDays) ToTime() time.Time { + return DaysToTime(d) } + +func (d DateDays) Before (days DateDays) bool { + return d < days } + +func (d DateDays) After (days DateDays) bool { + return d > days } + +func (d DateDays) Compare(days DateDays) int { + if d < days { + return -1 } + if d == days { + return 0 } + return 1 +} + +func (d DateDays) Min (days DateDays) DateDays { + if d > days { + return days + } + return d +} + +func (d DateDays) Max (days DateDays) DateDays { + if d < days { + return days + } + return d +} + + + + + + +func TimeToDays (time time.Time) DateDays { + _,x := time.Zone() + s := time.Unix() + int64(x) + if s >= 0 { + return DateDays(s/ secondsDay) } + return -DateDays((secondsDay -1 -s)/ secondsDay) +} + + +func DaysToTime(days DateDays) time.Time { + return time.Unix(int64(days) *secondsDay,0).UTC() } + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/times/date_days_range.go b/core/times/date_days_range.go new file mode 100644 index 0000000..3a4b940 --- /dev/null +++ b/core/times/date_days_range.go @@ -0,0 +1,92 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name date_days_range.go +// Created by DEV +// Modified 21/02/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +package times + +import "activething.com/go/gogo/core/opts" + +type ( + + DateDaysRange struct { + Start DateDays + End DateDays + } + + +) + +func NewDateRange (options ...opts.OptionFnc[DateDaysRange]) *DateDaysRange { + return opts.Apply[DateDaysRange](&DateDaysRange{ + // + },options...)} + + + + + +func (r DateDaysRange) IsZero () bool { + return r.End-r.Start <= 0 } + + +func (r DateDaysRange) Size () DateDays { + return DateDays(r.End -r.Start) } + + +func (r DateDaysRange) Contains (days DateDays) bool { + if r.IsZero() { + return false } + return r.Start < days && r.End > days +} + + +func (r DateDaysRange) ContainsRange (drange DateDaysRange) bool { + if r.IsZero() { + return false } + return r.Start > drange.Start && r.End < drange.End +} + + +func (r DateDaysRange) IsRangeOverlap (drange DateDaysRange) bool { + if r.IsZero() { + return false } + if r.Start == drange.Start || r.Start == drange.End || r.End == drange.End { + return true } + if r.Start > drange.Start { + return drange.End < r.End + } + return r.End > drange.Start +} + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/times/duration_formatter.go b/core/times/duration_formatter.go index 02eca7d..d7b059f 100644 --- a/core/times/duration_formatter.go +++ b/core/times/duration_formatter.go @@ -43,7 +43,9 @@ type ( ) -func (f FormatDurationFnc) FormatDuration (dur time.Duration, dst []byte) []byte { return f(dur,dst) } +func (f FormatDurationFnc) FormatDuration (dur time.Duration, dst []byte) []byte { + return f(dur,dst) } + func WrapDurationFormatterQuoted (dfm DurationFormatter, qte byte) DurationFormatter { return FormatDurationFnc(func(tme time.Duration, dst []byte) []byte { @@ -55,8 +57,7 @@ func WrapDurationFormatterQuoted (dfm DurationFormatter, qte byte) DurationForma func DurationMillis (dur time.Duration, dst []byte) []byte { - return strconv.AppendFloat(dst, float64(dur)/float64(time.Millisecond), 'f', -1, 64) -} + return strconv.AppendFloat(dst, float64(dur)/float64(time.Millisecond), 'f', -1, 64) } diff --git a/core/times/go.mod b/core/times/go.mod index 711ac87..65e52ba 100644 --- a/core/times/go.mod +++ b/core/times/go.mod @@ -1,4 +1,5 @@ -module activething.com/go/gogog/core/times +module activething.com/go/gogo/core/times + go 1.20 \ No newline at end of file diff --git a/core/times/gogo.go b/core/times/gogo.go index a4b9a3f..f11ace8 100644 --- a/core/times/gogo.go +++ b/core/times/gogo.go @@ -2,11 +2,11 @@ // Project atila // Active Thing (activething.com) git.activething.com/go // -// File name rkey.go +// File name gogo.go // Created by DEV -// Modified 05/02/2024 +// Modified 21/02/2024 // -// Copyright 2024 activething.com +// Copyright 2024 activething.com // ------------------------------------------------------------------------ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,49 +23,49 @@ package times -import ( - "activething.com/go/gogo/core/errs" -) +import "activething.com/go/gogo/core/errs" +const( -var ( + secondsDay = 24 * 60 * 60 + +) +var ( + G = struct { - ErrExpired errs.ErrCode - ErrTimeout errs.ErrCode - ErrIntervalInvalid errs.ErrCode - ErrNotStarted errs.ErrCode - ErrNotPaused errs.ErrCode - ErrAlreadyStarted errs.ErrCode - ErrTransitionInvalid errs.ErrCode - ErrTimerTaskInvalid errs.ErrCode - } { - - ErrExpired: errs.ErrCode("expired"), - ErrTimeout: errs.ErrCode("timeout"), - ErrIntervalInvalid: errs.ErrCode("interval_invalid"), - ErrNotStarted: errs.ErrCode("not_started"), - ErrNotPaused: errs.ErrCode("not_paused"), - ErrAlreadyStarted: errs.ErrCode("already_started"), - ErrTransitionInvalid:errs.ErrCode("transition_invalid"), - ErrTimerTaskInvalid: errs.ErrCode("timer_task_invalid"), - } + ErrInvalidDateRange errs.ErrCode + }{ + + ErrInvalidDateRange : errs.ErrCode("core:times.invalid-date-range"), + } ) -/* - :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. - "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. - SIDDHARTA - - HERMANN HESSE - - ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +func IsYearLeap (year int) bool { + return year%4 == 0 && (year%100 != 0 || year%400 == 0) } + + +func DaysInYear (year int) int { + if IsYearLeap(year) { + return 366 } + return 365 +} + + +func DaysIn (year, month int) int { + if month <= 0 || month > 12 { + return 0 } + d := [12]int{ 31,28,31,30,31,30,31,30,31,30,31 } + if month == 2 && IsYearLeap(year) { + return 29 } + return d[month] +} -*/ diff --git a/core/times/time_formatter.go b/core/times/time_formatter.go index b9f1f59..d8f86ed 100644 --- a/core/times/time_formatter.go +++ b/core/times/time_formatter.go @@ -43,7 +43,8 @@ type ( ) -func (f FormatTimeFnc) FormatTime (tme time.Time, dst []byte) []byte { return f(tme,dst) } +func (f FormatTimeFnc) FormatTime (tme time.Time, dst []byte) []byte { + return f(tme,dst) } @@ -58,28 +59,23 @@ func WrapTimeFormatterQuoted (tmf TimeFormatter, qte byte) TimeFormatter { func TimeRFC3339Nano(tme time.Time, dst []byte) []byte { - return tme.AppendFormat(dst, time.RFC3339Nano) -} + return tme.AppendFormat(dst, time.RFC3339Nano) } func TimeANSIC(tme time.Time, dst []byte) []byte { - return tme.AppendFormat(dst, time.ANSIC) -} + return tme.AppendFormat(dst, time.ANSIC) } func TimeUnixDate(tme time.Time, dst []byte) []byte { - return tme.AppendFormat(dst, time.UnixDate) -} + return tme.AppendFormat(dst, time.UnixDate) } func TimeRubyDate(tme time.Time, dst []byte) []byte { - return tme.AppendFormat(dst, time.RubyDate) -} + return tme.AppendFormat(dst, time.RubyDate) } func TimeRFC822(tme time.Time, dst []byte) []byte { - return tme.AppendFormat(dst, time.RFC822) -} + return tme.AppendFormat(dst, time.RFC822) } func TimeRFC822Z(tme time.Time, dst []byte) []byte { diff --git a/go.work b/go.work index 906cecf..0b1b990 100644 --- a/go.work +++ b/go.work @@ -12,6 +12,7 @@ use ( ./core/syncs ./core/results ./core/times + ./core/timers ./core/crypts ./core/values