Skip to content

Commit

Permalink
feat(rx): add try/must item helpers (#227)
Browse files Browse the repository at this point in the history
  • Loading branch information
plastikfan committed Apr 16, 2024
1 parent e967c3c commit ffd50b0
Show file tree
Hide file tree
Showing 8 changed files with 439 additions and 63 deletions.
11 changes: 6 additions & 5 deletions enums/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ package enums
type ItemDiscriminator uint32

const (
ItemDiscUndefined ItemDiscriminator = 0
// ItemDiscNative enum value that represents the native type T.
//
ItemDiscNative ItemDiscriminator = 0
ItemDiscNative ItemDiscriminator = 1 << (iota - 1)

// ItemDiscBoolean enum value that represents a general boolean value
// typically used by predicate based operations eg All.
//
ItemDiscBoolean ItemDiscriminator = 1 << (iota - 1)
ItemDiscBoolean

// ItemDiscChan enum value that represents a channel of T
// ItemDiscWChan enum value that represents a channel of T
//
ItemDiscChan
ItemDiscWChan

// ItemDiscError enum value that represents an error
//
Expand Down Expand Up @@ -59,7 +60,7 @@ func init() {
ItemDescriptions = itemsDiscDescriptions{
ItemDiscNative: "native",
ItemDiscBoolean: "boolean",
ItemDiscChan: "channel",
ItemDiscWChan: "write channel",
ItemDiscError: "error",
ItemDiscNumber: "number",
ItemDiscTick: "tick",
Expand Down
5 changes: 4 additions & 1 deletion rx/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ loop:
case enums.ItemDiscBoolean:
resources.booleans = append(resources.booleans, item.Bool())

case enums.ItemDiscChan:
case enums.ItemDiscWChan:
Fail(fmt.Sprintf("NOT-IMPL yet for channel for: '%v'", item.Desc()))

case enums.ItemDiscError:
Expand All @@ -142,6 +142,9 @@ loop:
case enums.ItemDiscOpaque:
resources.opaques = append(resources.opaques, item.Opaque())

case enums.ItemDiscUndefined:
Fail(fmt.Sprintf("undefined value not handled for: '%v'", item.Desc()))

default:
Fail(fmt.Sprintf("value type not handled for: '%v'", item.Desc()))
}
Expand Down
18 changes: 18 additions & 0 deletions rx/errors.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package rx

import (
"fmt"

"github.com/snivilised/lorax/enums"
)

// MIT License

// Copyright (c) 2016 Joe Chasinga
Expand Down Expand Up @@ -39,3 +45,15 @@ type IndexOutOfBoundError struct {
func (e IndexOutOfBoundError) Error() string {
return "index out of bound: " + e.error
}

type TryError[T any] struct {
error string
item Item[T]
expected enums.ItemDiscriminator
}

func (e TryError[T]) Error() string {
return fmt.Sprintf("expected item to be : '%v', but is: '%v' (%+v)",
enums.ItemDescriptions[e.expected], enums.ItemDescriptions[e.item.disc], e.item,
)
}
118 changes: 61 additions & 57 deletions rx/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,26 +56,16 @@ func Of[T any](v T) Item[T] {
}
}

// Returns the native value of item
func (it Item[T]) Of() T {
return it.aux.(T)
}
// Zero creates a zero value item.
func Zero[T any]() Item[T] {
var (
zero T
)

// Ch creates an item from a channel
func Ch[T any](ch any) Item[T] {
if c, ok := ch.(chan<- Item[T]); ok {
return Item[T]{
aux: c,
disc: enums.ItemDiscChan,
}
return Item[T]{
V: zero,
disc: enums.ItemDiscNative,
}

panic("temp: invalid ch type")
}

// Returns the channel value of item
func (it Item[T]) Ch() chan<- Item[T] {
return it.aux.(chan<- Item[T])
}

// Error creates an item from an error.
Expand All @@ -86,42 +76,6 @@ func Error[T any](err error) Item[T] {
}
}

// Returns the error value of item
func (it Item[T]) Error() error {
return it.aux.(error)
}

// Returns the error value of item
func (it Item[T]) Pulse() error {
return it.aux.(error)
}

// TV creates a type safe tick value instance
func TV[T any](tv int) Item[T] {
return Item[T]{
aux: tv,
disc: enums.ItemDiscTickValue,
}
}

// Returns the tick value of item
func (it Item[T]) TV() int {
return it.aux.(int)
}

// Num creates a type safe tick value instance
func Num[T any](n NumVal) Item[T] {
return Item[T]{
aux: n,
disc: enums.ItemDiscNumber,
}
}

// Returns the tick value of item
func (it Item[T]) Num() NumVal {
return it.aux.(NumVal)
}

// Bool creates a type safe boolean instance
func Bool[T any](b bool) Item[T] {
return Item[T]{
Expand Down Expand Up @@ -151,6 +105,36 @@ func False[T any]() Item[T] {
}
}

// WCh creates an item from a channel
func WCh[T any](ch any) Item[T] {
if c, ok := ch.(chan<- Item[T]); ok {
return Item[T]{
aux: c,
disc: enums.ItemDiscWChan,
}
}

panic("temp: invalid ch type")
}

// Returns the channel value of item
func (it Item[T]) Ch() chan<- Item[T] {
return it.aux.(chan<- Item[T])
}

// Num creates a type safe tick value instance
func Num[T any](n NumVal) Item[T] {
return Item[T]{
aux: n,
disc: enums.ItemDiscNumber,
}
}

// Returns the tick value of item
func (it Item[T]) Num() NumVal {
return it.aux.(NumVal)
}

// Opaque creates an item from any type of value
func Opaque[T any](o any) Item[T] {
return Item[T]{
Expand All @@ -164,6 +148,26 @@ func (it Item[T]) Opaque() any {
return it.aux
}

// TV creates a type safe tick instance (no value)
func Tick[T any]() Item[T] {
return Item[T]{
disc: enums.ItemDiscTick,
}
}

// TV creates a type safe tick value instance
func TV[T any](tv int) Item[T] {
return Item[T]{
aux: tv,
disc: enums.ItemDiscTickValue,
}
}

// Returns the tick value of item
func (it Item[T]) TV() int {
return it.aux.(int)
}

// Disc returns the discriminator of the item
func (it Item[T]) Disc() enums.ItemDiscriminator {
return it.disc
Expand Down Expand Up @@ -234,7 +238,7 @@ func sendViaRefCh[T any](ctx context.Context, inCh reflect.Value, ch chan<- Item

switch item := vItem.(type) {
default:
Ch[T](item).SendContext(ctx, ch)
WCh[T](item).SendContext(ctx, ch)

case error:
Error[T](item).SendContext(ctx, ch)
Expand All @@ -244,12 +248,12 @@ func sendViaRefCh[T any](ctx context.Context, inCh reflect.Value, ch chan<- Item

// IsValue checks if an item is a value.
func (it Item[T]) IsValue() bool {
return it.disc == 0
return (it.disc & enums.ItemDiscNative) > 0
}

// IsCh checks if an item is an error.
func (it Item[T]) IsCh() bool {
return (it.disc & enums.ItemDiscChan) > 0
return (it.disc & enums.ItemDiscWChan) > 0
}

// IsError checks if an item is an error.
Expand Down
114 changes: 114 additions & 0 deletions rx/must-try.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package rx

import (
"github.com/snivilised/lorax/enums"
)

type tryFunc[T, O any] func(Item[T]) (O, error)

func must[T, O any](item Item[T], fn tryFunc[T, O]) (result O) {
var (
err error
)

if result, err = fn(item); err != nil {
panic(err)
}

return result
}

func try[T, O any](item Item[T], expected enums.ItemDiscriminator) (O, error) {
if value, ok := item.aux.(O); ok {
return value, nil
}

var (
zero O
)

return zero, TryError[T]{
item: item,
expected: expected,
}
}

// TryBool is a helper function that assists the client in interpreting
// a boolean item received via a channel. If the item it not a boolean,
// an error is returned, otherwise the returned value is the underlying
// boolean value.
func TryBool[T any](item Item[T]) (bool, error) {
return try[T, bool](item, enums.ItemDiscBoolean)
}

// MustBool is a helper function that assists the client in interpreting
// a boolean item received via a channel. If the item it not a boolean,
// a panic is raised, otherwise the returned value is the underlying
// boolean value.
func MustBool[T any](item Item[T]) bool {
return must(item, TryBool[T])
}

// TryWCh is a helper function that assists the client in interpreting
// a write chan item received via a channel. If the item it not a write chan,
// an error is returned, otherwise the returned value is the underlying
// write chan value.
func TryWCh[T any](item Item[T]) (chan<- Item[T], error) {
return try[T, chan<- Item[T]](item, enums.ItemDiscWChan)
}

// MustWCh is a helper function that assists the client in interpreting
// a write chan item received via a channel. If the item it not a write chan,
// a panic is raised, otherwise the returned value is the underlying
// write chan value.
func MustWCh[T any](item Item[T]) chan<- Item[T] {
return must(item, TryWCh[T])
}

// TryNum is a helper function that assists the client in interpreting
// an integer item received via a channel. If the item it not an integer,
// an error is returned, otherwise the returned value is the underlying
// integer value.
func TryNum[T any](item Item[T]) (NumVal, error) {
return try[T, NumVal](item, enums.ItemDiscNumber)
}

// MustNum is a helper function that assists the client in interpreting
// an integer item received via a channel. If the item it not an integer,
// a panic is raised, otherwise the returned value is the underlying
// integer value.
func MustNum[T any](item Item[T]) NumVal {
return must(item, TryNum[T])
}

// TryOpaque is a helper function that assists the client in interpreting
// an opaque item received via a channel. If the item it not of the custom
// type O, an error is returned, otherwise the returned value is the underlying
// custom value.
func TryOpaque[T, O any](item Item[T]) (O, error) {
return try[T, O](item, enums.ItemDiscOpaque)
}

// MustOpaque is a helper function that assists the client in interpreting
// an opaque item received via a channel. If the item it not of the custom
// type O, a panic is raised, otherwise the returned value is the underlying
// custom value.
func MustOpaque[T, O any](item Item[T]) O {
return must[T, O](item, TryOpaque[T])
}

// TryTV is a helper function that assists the client in interpreting
// an integer based tick value item received via a channel. If the item
// it not a tick value, an error is returned, otherwise the returned value
// is the underlying integer value.
func TryTV[T any](item Item[T]) (int, error) {
return try[T, int](item, enums.ItemDiscTickValue)
}

// TryTV is a helper function that assists the client in interpreting
// an integer based tick value item received via a channel. If the item
// it not a tick value, a panic is raised, otherwise the returned value
// is the underlying integer value.
func MustTV[T any](item Item[T]) int {
return must(item, TryTV[T])
}
Loading

0 comments on commit ffd50b0

Please sign in to comment.