-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feat] dataconv/types: generics EitherOrNone (#103)
* drafts * fix it * add testing code * for types formal * for details * more corners * more type string * less lines
- Loading branch information
Showing
3 changed files
with
436 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package types | ||
|
||
import ( | ||
"fmt" | ||
|
||
"go.starlark.net/starlark" | ||
) | ||
|
||
// EitherOrNone is an Unpacker that converts a Starlark None, A, or B to Go's starlark.Value. | ||
type EitherOrNone[A starlark.Value, B starlark.Value] struct { | ||
value starlark.Value | ||
isNone bool | ||
isTypeA bool | ||
isTypeB bool | ||
} | ||
|
||
// NewEitherOrNone creates and returns a new EitherOrNone. | ||
func NewEitherOrNone[A starlark.Value, B starlark.Value]() *EitherOrNone[A, B] { | ||
return &EitherOrNone[A, B]{isNone: true} | ||
} | ||
|
||
// Unpack implements the starlark.Unpacker interface. | ||
func (e *EitherOrNone[A, B]) Unpack(v starlark.Value) error { | ||
if e == nil { | ||
return fmt.Errorf("nil pointer") | ||
} | ||
if _, ok := v.(starlark.NoneType); ok { | ||
e.value = nil | ||
e.isNone, e.isTypeA, e.isTypeB = true, false, false | ||
} else if a, ok := v.(A); ok { | ||
e.value = a | ||
e.isNone, e.isTypeA, e.isTypeB = false, true, false | ||
} else if b, ok := v.(B); ok { | ||
e.value = b | ||
e.isNone, e.isTypeA, e.isTypeB = false, false, true | ||
} else { | ||
var zeroA A | ||
var zeroB B | ||
return fmt.Errorf("expected %T or %T or None, got %s", zeroA, zeroB, v.Type()) | ||
} | ||
return nil | ||
} | ||
|
||
// IsNone returns true if the value is None. | ||
func (e *EitherOrNone[A, B]) IsNone() bool { | ||
return e != nil && e.isNone | ||
} | ||
|
||
// IsTypeA returns true if the value is of type A. | ||
func (e *EitherOrNone[A, B]) IsTypeA() bool { | ||
return e != nil && e.isTypeA | ||
} | ||
|
||
// IsTypeB returns true if the value is of type B. | ||
func (e *EitherOrNone[A, B]) IsTypeB() bool { | ||
return e != nil && e.isTypeB | ||
} | ||
|
||
// Value returns the underlying value. You can use IsTypeA and IsTypeB to check which type it is. | ||
func (e *EitherOrNone[A, B]) Value() starlark.Value { | ||
if e == nil { | ||
var zero starlark.Value | ||
return zero | ||
} | ||
return e.value | ||
} | ||
|
||
// ValueA returns the value of type A, if available, and a boolean indicating its presence. | ||
func (e *EitherOrNone[A, B]) ValueA() (A, bool) { | ||
if e != nil && e.isTypeA { | ||
return e.value.(A), true | ||
} | ||
var zero A | ||
return zero, false | ||
} | ||
|
||
// ValueB returns the value of type B, if available, and a boolean indicating its presence. | ||
func (e *EitherOrNone[A, B]) ValueB() (B, bool) { | ||
if e != nil && e.isTypeB { | ||
return e.value.(B), true | ||
} | ||
var zero B | ||
return zero, false | ||
} | ||
|
||
// Type returns the type of the underlying value. | ||
func (e *EitherOrNone[A, B]) Type() string { | ||
if e == nil { | ||
return "NilReceiver" | ||
} | ||
if e.isNone { | ||
return starlark.None.Type() | ||
} | ||
if e.isTypeA { | ||
var a A | ||
return a.Type() | ||
} | ||
if e.isTypeB { | ||
var b B | ||
return b.Type() | ||
} | ||
return "Unknown" | ||
} | ||
|
||
// Unpacker interface implementation check | ||
var ( | ||
_ starlark.Unpacker = (*EitherOrNone[*starlark.List, *starlark.Dict])(nil) | ||
_ starlark.Unpacker = (*EitherOrNone[starlark.String, starlark.Int])(nil) | ||
) |
Oops, something went wrong.