From eab38629013e34b4490be4d665142a1357c97156 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Wed, 2 Apr 2025 18:09:46 +0200 Subject: demonstration of refinement types without self-referential types The big "yuck" about this can be seen in the LiteralValue invocations in the test code. Calling NewValue or LiteralValue is extremely convoluted and would likely need to be wrapped through additional boilerplate at the concrete type declaration site. --- refined/value.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 refined/value.go (limited to 'refined/value.go') diff --git a/refined/value.go b/refined/value.go new file mode 100644 index 0000000..0d480ba --- /dev/null +++ b/refined/value.go @@ -0,0 +1,61 @@ +/******************************************************************************* +* Copyright 2025 Stefan Majewsky +* SPDX-License-Identifier: Apache-2.0 +* Refer to the file "LICENSE" for details. +*******************************************************************************/ + +package refined + +import ( + "encoding/json" + + //nolint:staticcheck // this dot import is fine (ST1001) + . "github.com/majewsky/gg/option" +) + +// NOTE: The zero value is illegal and will panic on use. +type Value[V any, C Condition[V]] struct { + value Option[V] +} + +type Condition[V any] interface { + MatchesValue(V) error +} + +func NewValue[V any, C Condition[V]](value V) (Value[V, C], error) { + var cond C + err := cond.MatchesValue(value) + if err == nil { + return Value[V, C]{value: Some(value)}, nil + } else { + return Value[V, C]{}, err + } +} + +func LiteralValue[V any, C Condition[V]](value V) Value[V, C] { + var cond C + err := cond.MatchesValue(value) + if err == nil { + return Value[V, C]{value: Some(value)} + } else { + panic(err.Error()) + } +} + +func (v Value[V, C]) Raw() V { + return v.value.UnwrapOrPanic("illegal use of zero-valued instance of refined.Value") +} + +func (v *Value[V, C]) UnmarshalJSON(buf []byte) error { + var value V + err := json.Unmarshal(buf, &value) + if err != nil { + return err + } + *v, err = NewValue[V, C](value) + return err +} + +func (v Value[V, C]) MarshalJSON() ([]byte, error) { + return json.Marshal(v.Raw()) +} -- cgit v1.2.3