diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2025-04-03 23:31:23 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2025-07-01 15:09:20 +0200 |
| commit | a6dd82541baf2699ae53d6e7582bf0b9e2186bbd (patch) | |
| tree | 60141fd6452cc58ae400139dbf5420465328d9cc | |
| parent | 3b2c63e67fd72abc42bf792b2b30809241732107 (diff) | |
| download | go-gg-a6dd82541baf2699ae53d6e7582bf0b9e2186bbd.tar.gz | |
another sketch for refinement types
| -rw-r--r-- | refined/value.go | 72 | ||||
| -rw-r--r-- | refined/value_test.go | 30 |
2 files changed, 102 insertions, 0 deletions
diff --git a/refined/value.go b/refined/value.go new file mode 100644 index 0000000..cfaa412 --- /dev/null +++ b/refined/value.go @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net> +// SPDX-License-Identifier: Apache-2.0 + +package refined + +import ( + "cmp" + "errors" + "regexp" + + . "github.com/majewsky/gg/option" +) + +type Scalar[S any, V any] struct { + value Option[V] +} + +func (s Scalar[S, V]) Raw() V { + return s.value.UnwrapOrPanic("TODO 1") +} + +func New[S IsAScalar[S, V], V any](value V) (S, error) { + var empty S + return empty.Refine(Challenge[S, V]{Value: value, valid: true}) +} + +func Literal[S IsAScalar[S, V], V any](value V) S { + var empty S + s, err := empty.Refine(Challenge[S, V]{Value: value, valid: true}) + if err != nil { + panic("TODO 2") + } + return s +} + +type IsAScalar[S any, V any] interface { + Refine(Challenge[S, V]) (S, error) +} + +type Challenge[S any, V any] struct { + Value V + valid bool +} + +func (c Challenge[S, V]) Accept() Scalar[S, V] { + if !c.valid { + panic("broken Challenge object") + } + return Scalar[S, V]{value: Some(c.Value)} +} + +func RangeCheck[S any, V cmp.Ordered](c Challenge[S, V], minimum, maximum V) (Scalar[S, V], error) { + if minimum <= maximum && c.Value >= minimum && c.Value <= maximum { + return c.Accept(), nil + } + return Scalar[S, V]{}, errors.New("TODO 3") +} + +func RegexpCheck[S any, V ~string](c Challenge[S, V], rx *regexp.Regexp) (Scalar[S, V], error) { + if rx.MatchString(string(c.Value)) { + return c.Accept(), nil + } + return Scalar[S, V]{}, errors.New("TODO 4") +} + +func NotZeroCheck[S any, V comparable](c Challenge[S, V]) (Scalar[S, V], error) { + var zero V + if c.Value != zero { + return c.Accept(), nil + } + return Scalar[S, V]{}, errors.New("TODO 5") +} diff --git a/refined/value_test.go b/refined/value_test.go new file mode 100644 index 0000000..aaf3706 --- /dev/null +++ b/refined/value_test.go @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net> +// SPDX-License-Identifier: Apache-2.0 + +package refined_test + +import ( + "testing" + + . "github.com/majewsky/gg/internal/test" + "github.com/majewsky/gg/refined" +) + +type DiceRoll struct { + refined.Scalar[DiceRoll, int] +} + +func (DiceRoll) Refine(c refined.Challenge[DiceRoll, int]) (DiceRoll, error) { + s, err := refined.RangeCheck(c, 1, 6) + return DiceRoll{s}, err +} + +func TestDiceRoll(t *testing.T) { + d := refined.Literal[DiceRoll](5) + AssertEqual(t, d.Raw(), 5) + + var err error + d, err = refined.New[DiceRoll](7) + AssertEqual(t, d, DiceRoll{}) + AssertEqual(t, err.Error(), "TODO 3") +} |
