initial commits
parent
d1e874fe9a
commit
fa844fd34c
|
@ -0,0 +1,114 @@
|
|||
package tmp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Temporal[T any] struct {
|
||||
value T
|
||||
until int64 // unit-time
|
||||
istemporary bool
|
||||
ispermanent bool
|
||||
}
|
||||
|
||||
func Nothing[T any]() Temporal[T] {
|
||||
var nothing Temporal[T]
|
||||
|
||||
return nothing
|
||||
}
|
||||
|
||||
func Permanent[T any](value T) Temporal[T] {
|
||||
return Temporal[T]{
|
||||
ispermanent:true,
|
||||
value:value,
|
||||
}
|
||||
}
|
||||
|
||||
func Temporary[T any](value T, until int64) Temporal[T] {
|
||||
return Temporal[T]{
|
||||
istemporary:true,
|
||||
value:value,
|
||||
until:until,
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) isnothing() bool {
|
||||
return !receiver.istemporary && !receiver.ispermanent
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) Filter(fn func(T)bool) Temporal[T] {
|
||||
if receiver.isnothing() {
|
||||
return Nothing[T]()
|
||||
}
|
||||
if receiver.IsDefunct() {
|
||||
return Nothing[T]()
|
||||
}
|
||||
|
||||
if !fn(receiver.value) {
|
||||
return Nothing[T]()
|
||||
}
|
||||
|
||||
return receiver
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) Get() (T, bool) {
|
||||
return receiver.value, receiver.IsExtant()
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) GoString() string {
|
||||
if receiver.isnothing() {
|
||||
return fmt.Sprintf("tmp.Nothing[%T]()", receiver.value)
|
||||
}
|
||||
if receiver.ispermanent {
|
||||
return fmt.Sprintf("tmp.Permanent[%T](%#v)", receiver.value, receiver.value)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("tmp.Temporary[%T](%#v, %d)", receiver.value, receiver.value, receiver.until)
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) IsDefunct() bool {
|
||||
if receiver.ispermanent {
|
||||
return false
|
||||
}
|
||||
|
||||
if receiver.istemporary {
|
||||
var now int64 = time.Now().Unix()
|
||||
|
||||
return receiver.until < now
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) IsExtant() bool {
|
||||
if receiver.ispermanent {
|
||||
return true
|
||||
}
|
||||
|
||||
if receiver.istemporary {
|
||||
var now int64 = time.Now().Unix()
|
||||
|
||||
return now <= receiver.until
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) WhenNothing(fn func()) {
|
||||
if receiver.isnothing() {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) WhenDefunct(fn func()) {
|
||||
if receiver.IsDefunct() {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver Temporal[T]) WhenExtant(fn func(T)) {
|
||||
if receiver.IsExtant() {
|
||||
fn(receiver.value)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package tmp_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sourcecode.social/reiver/go-tmp"
|
||||
)
|
||||
|
||||
func TestTemporal_Filter_int(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Temporal tmp.Temporal[int]
|
||||
Expected tmp.Temporal[int]
|
||||
}{
|
||||
{
|
||||
Temporal: tmp.Nothing[int](),
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Temporal: tmp.Permanent[int](-2),
|
||||
Expected: tmp.Permanent[int](-2),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Permanent[int](-1),
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Permanent[int](0),
|
||||
Expected: tmp.Permanent[int](0),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Permanent[int](1),
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Permanent[int](2),
|
||||
Expected: tmp.Permanent[int](2),
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Temporal: tmp.Temporary[int](-2, 9_223_372_036_854_775_807), // int64 problem
|
||||
Expected: tmp.Temporary[int](-2, 9_223_372_036_854_775_807),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](-1, 9_223_372_036_854_775_806), // int64 problem
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](0, 9_223_372_036_854_775_805), // int64 problem
|
||||
Expected: tmp.Temporary[int](0, 9_223_372_036_854_775_805),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](1, 9_223_372_036_854_775_804), // int64 problem
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](2, 9_223_372_036_854_775_803),
|
||||
Expected: tmp.Temporary[int](2, 9_223_372_036_854_775_803), // int64 problem
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Temporal: tmp.Temporary[int](-2, 111), // supposed to be in the past
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](-1, 111), // supposed to be in the past
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](0, 111), // supposed to be in the past
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](1, 111), // supposed to be in the past
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[int](2, 111), // supposed to be in the past
|
||||
Expected: tmp.Nothing[int](),
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
fn := func(value int) bool {
|
||||
return 0 == (value % 2)
|
||||
}
|
||||
|
||||
actual := test.Temporal.Filter(fn)
|
||||
expected := test.Expected
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %#v", expected)
|
||||
t.Logf("ACTUAL: %#v", actual)
|
||||
/////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
package tmp_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
|
||||
"sourcecode.social/reiver/go-tmp"
|
||||
)
|
||||
|
||||
func TestTemporal_GoString_permanent(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Value any
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Value: "",
|
||||
Expected: `tmp.Permanent[string]("")`,
|
||||
},
|
||||
{
|
||||
Value: "once twice thrice fource",
|
||||
Expected: `tmp.Permanent[string]("once twice thrice fource")`,
|
||||
},
|
||||
{
|
||||
Value: "apple banana cherry",
|
||||
Expected: `tmp.Permanent[string]("apple banana cherry")`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: uint8 (0x0),
|
||||
Expected: `tmp.Permanent[uint8](0x0)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0x1),
|
||||
Expected: `tmp.Permanent[uint8](0x1)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0x2),
|
||||
Expected: `tmp.Permanent[uint8](0x2)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0xfe),
|
||||
Expected: `tmp.Permanent[uint8](0xfe)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0xff),
|
||||
Expected: `tmp.Permanent[uint8](0xff)`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: uint16 (0x0),
|
||||
Expected: `tmp.Permanent[uint16](0x0)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x1),
|
||||
Expected: `tmp.Permanent[uint16](0x1)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x2),
|
||||
Expected: `tmp.Permanent[uint16](0x2)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xfe),
|
||||
Expected: `tmp.Permanent[uint16](0xfe)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xff),
|
||||
Expected: `tmp.Permanent[uint16](0xff)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x100),
|
||||
Expected: `tmp.Permanent[uint16](0x100)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x101),
|
||||
Expected: `tmp.Permanent[uint16](0x101)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x102),
|
||||
Expected: `tmp.Permanent[uint16](0x102)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xfffe),
|
||||
Expected: `tmp.Permanent[uint16](0xfffe)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xffff),
|
||||
Expected: `tmp.Permanent[uint16](0xffff)`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: struct { A string; B int }{A:"joeblow",B:7},
|
||||
Expected: `tmp.Permanent[struct { A string; B int }](struct { A string; B int }{A:"joeblow", B:7})`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
op := tmp.Permanent(test.Value)
|
||||
gostring := op.GoString()
|
||||
|
||||
{
|
||||
expected := test.Expected
|
||||
actual := gostring
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual go-string is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %q", expected)
|
||||
t.Logf("ACTUAL: %q", actual)
|
||||
t.Logf("VALUE-TYPE: %T", test.Value)
|
||||
t.Logf("VALUE: %#v", test.Value)
|
||||
//////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemporal_GoString_nothing(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Temporal fmt.GoStringer
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Temporal: tmp.Nothing[string](),
|
||||
Expected: `tmp.Nothing[string]()`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Temporal: tmp.Nothing[int8](),
|
||||
Expected: `tmp.Nothing[int8]()`,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Nothing[int16](),
|
||||
Expected: `tmp.Nothing[int16]()`,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Nothing[int32](),
|
||||
Expected: `tmp.Nothing[int32]()`,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Nothing[int64](),
|
||||
Expected: `tmp.Nothing[int64]()`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Temporal: tmp.Nothing[uint8](),
|
||||
Expected: `tmp.Nothing[uint8]()`,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Nothing[uint16](),
|
||||
Expected: `tmp.Nothing[uint16]()`,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Nothing[uint32](),
|
||||
Expected: `tmp.Nothing[uint32]()`,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Nothing[uint64](),
|
||||
Expected: `tmp.Nothing[uint64]()`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
expected := test.Expected
|
||||
actual := test.Temporal.GoString()
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual go-string value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED GO-STRING: %q", expected)
|
||||
t.Logf("ACTUAL GO-STRING: %q", actual)
|
||||
t.Logf("TYPE: %T", test.Temporal)
|
||||
/////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemporal_GoString_temporary(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Value any
|
||||
Until int64
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Value: "",
|
||||
Until: 0,
|
||||
Expected: `tmp.Temporary[string]("", 0)`,
|
||||
},
|
||||
{
|
||||
Value: "once twice thrice fource",
|
||||
Until: 1234,
|
||||
Expected: `tmp.Temporary[string]("once twice thrice fource", 1234)`,
|
||||
},
|
||||
{
|
||||
Value: "apple banana cherry",
|
||||
Until: 979899,
|
||||
Expected: `tmp.Temporary[string]("apple banana cherry", 979899)`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: uint8 (0x0),
|
||||
Until: 101,
|
||||
Expected: `tmp.Temporary[uint8](0x0, 101)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0x1),
|
||||
Until: 111,
|
||||
Expected: `tmp.Temporary[uint8](0x1, 111)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0x2),
|
||||
Until: 121,
|
||||
Expected: `tmp.Temporary[uint8](0x2, 121)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0xfe),
|
||||
Until: 989,
|
||||
Expected: `tmp.Temporary[uint8](0xfe, 989)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0xff),
|
||||
Until: 999,
|
||||
Expected: `tmp.Temporary[uint8](0xff, 999)`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: uint16 (0x0),
|
||||
Until: 303,
|
||||
Expected: `tmp.Temporary[uint16](0x0, 303)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x1),
|
||||
Until: 313,
|
||||
Expected: `tmp.Temporary[uint16](0x1, 313)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x2),
|
||||
Until: 323,
|
||||
Expected: `tmp.Temporary[uint16](0x2, 323)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xfe),
|
||||
Until: 383,
|
||||
Expected: `tmp.Temporary[uint16](0xfe, 383)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xff),
|
||||
Until: 393,
|
||||
Expected: `tmp.Temporary[uint16](0xff, 393)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x100),
|
||||
Until: 3003,
|
||||
Expected: `tmp.Temporary[uint16](0x100, 3003)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x101),
|
||||
Until: 3113,
|
||||
Expected: `tmp.Temporary[uint16](0x101, 3113)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x102),
|
||||
Until: 3223,
|
||||
Expected: `tmp.Temporary[uint16](0x102, 3223)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xfffe),
|
||||
Until: 3883,
|
||||
Expected: `tmp.Temporary[uint16](0xfffe, 3883)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xffff),
|
||||
Until: 3993,
|
||||
Expected: `tmp.Temporary[uint16](0xffff, 3993)`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: struct { A string; B int }{A:"joeblow",B:7},
|
||||
Until: 9876543210,
|
||||
Expected: `tmp.Temporary[struct { A string; B int }](struct { A string; B int }{A:"joeblow", B:7}, 9876543210)`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
op := tmp.Temporary(test.Value, test.Until)
|
||||
gostring := op.GoString()
|
||||
|
||||
{
|
||||
expected := test.Expected
|
||||
actual := gostring
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual go-string is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %q", expected)
|
||||
t.Logf("ACTUAL: %q", actual)
|
||||
t.Logf("VALUE-TYPE: %T", test.Value)
|
||||
t.Logf("VALUE: %#v", test.Value)
|
||||
//////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package tmp_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
|
||||
"sourcecode.social/reiver/go-tmp"
|
||||
)
|
||||
|
||||
func TestTemporal_IsDefunct(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Temporal tmp.Temporal[string]
|
||||
Expected bool
|
||||
}{
|
||||
{
|
||||
Temporal: tmp.Nothing[string](),
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Permanent[string]("forever"),
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[string]("expired", time.Now().Unix()-999), // supposed to be in the pastasx
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
Temporal: tmp.Temporary[string]("not-expired", time.Now().Unix()+99999),
|
||||
Expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
actual := test.Temporal.IsDefunct()
|
||||
expected := test.Expected
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual value for is-defunct is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %t", expected)
|
||||
t.Logf("ACTUAL: %t", actual)
|
||||
t.Logf("TEMPORAL: %#v", test.Temporal)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package tmp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTemporal_IsNothing(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Temporal Temporal[string]
|
||||
Expected bool
|
||||
}{
|
||||
{
|
||||
Temporal: Nothing[string](),
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
Temporal: Permanent[string]("forever"),
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
Temporal: Temporary[string]("expired", time.Now().Unix()-999),
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
Temporal: Temporary[string]("not-expired", time.Now().Unix()+99999),
|
||||
Expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
actual := test.Temporal.isnothing()
|
||||
expected := test.Expected
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual value for is-defunct is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %t", expected)
|
||||
t.Logf("ACTUAL: %t", actual)
|
||||
t.Logf("TEMPORAL: %#v", test.Temporal)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue