diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-24 18:41:37 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-24 18:41:37 +0300 |
| commit | f3cfcb0a95c6ce1662f0cb2c4eae10b3bf37a7bd (patch) | |
| tree | cc87ff8bff5306c7fc7d4d90871d327173e179a5 | |
| parent | 1b31b4a6bbf4b9ae371801d631c8eb692f17efb6 (diff) | |
fix(rpn): complete DIP for MetricRegistry — use MetricReader/MetricWriter interfaces (task ek)
| -rw-r--r-- | internal/rpn/metric_registry.go | 8 | ||||
| -rw-r--r-- | internal/rpn/operations.go | 6 | ||||
| -rw-r--r-- | internal/rpn/operations_arithmetic.go | 6 | ||||
| -rw-r--r-- | internal/rpn/operations_metric.go | 16 | ||||
| -rw-r--r-- | internal/rpn/operations_metric_cmd.go | 12 | ||||
| -rw-r--r-- | internal/rpn/rpn_state.go | 2 |
6 files changed, 33 insertions, 17 deletions
diff --git a/internal/rpn/metric_registry.go b/internal/rpn/metric_registry.go index a221e56..1aed264 100644 --- a/internal/rpn/metric_registry.go +++ b/internal/rpn/metric_registry.go @@ -28,6 +28,14 @@ type MetricReader interface { ListByCategory(cat Category) []*Metric } +// MetricWriter defines the write operations on a metric registry. +type MetricWriter interface { + Register(m *Metric) + RegisterAlias(alias, canonicalName string) + Unregister(name string) error + MarkExactMatch(names ...string) +} + // Global registry instance. var defaultRegistry *MetricRegistry var registryOnce sync.Once diff --git a/internal/rpn/operations.go b/internal/rpn/operations.go index f79457c..989ce87 100644 --- a/internal/rpn/operations.go +++ b/internal/rpn/operations.go @@ -13,7 +13,7 @@ type Operations struct { consts ConstantsProvider mode CalculationMode prefixMode PrefixMode - metricRegistry *MetricRegistry + metricRegistry MetricReader mu sync.RWMutex } @@ -38,8 +38,8 @@ var ( // NewOperations creates a new Operations instance with the given variable store. // Does not create a ConstantsProvider internally; caller must use SetConstants. // If no registry is provided, defaults to the global MetricRegistry. -func NewOperations(vars VariableStore, reg ...*MetricRegistry) *Operations { - r := GetMetricRegistry() +func NewOperations(vars VariableStore, reg ...MetricReader) *Operations { + r := MetricReader(GetMetricRegistry()) if len(reg) > 0 && reg[0] != nil { r = reg[0] } diff --git a/internal/rpn/operations_arithmetic.go b/internal/rpn/operations_arithmetic.go index 1c4252c..4468edb 100644 --- a/internal/rpn/operations_arithmetic.go +++ b/internal/rpn/operations_arithmetic.go @@ -24,7 +24,7 @@ func (o *Operations) binaryMetricOp( op string, compatCheck func(*Metric, *Metric) error, compute func(float64, float64) float64, - resultMetricFn func(*MetricRegistry, *Metric, *Metric) (*Metric, error), + resultMetricFn func(MetricReader, *Metric, *Metric) (*Metric, error), preChecks ...func(StackValue) error, ) error { a, b, err := popTwo(stack, op) @@ -85,7 +85,7 @@ func (o *Operations) Add(stack *Stack) error { return nil }, func(a, b float64) float64 { return a + b }, - func(reg *MetricRegistry, aM, bM *Metric) (*Metric, error) { + func(reg MetricReader, aM, bM *Metric) (*Metric, error) { return compatibleMetric(reg, aM, bM), nil }, ) @@ -102,7 +102,7 @@ func (o *Operations) Subtract(stack *Stack) error { return nil }, func(a, b float64) float64 { return a - b }, - func(reg *MetricRegistry, aM, bM *Metric) (*Metric, error) { + func(reg MetricReader, aM, bM *Metric) (*Metric, error) { return compatibleMetric(reg, aM, bM), nil }, ) diff --git a/internal/rpn/operations_metric.go b/internal/rpn/operations_metric.go index 64cce98..b621085 100644 --- a/internal/rpn/operations_metric.go +++ b/internal/rpn/operations_metric.go @@ -6,7 +6,7 @@ package rpn import "fmt" // resolveMetric returns the metric for a StackValue, defaulting to Cool if nil. -func resolveMetric(reg *MetricRegistry, n StackValue) (*Metric, error) { +func resolveMetric(reg MetricReader, n StackValue) (*Metric, error) { m := n.Metric() if m == nil { var ok bool @@ -59,7 +59,7 @@ func categoriesCompatible(a, b *Metric) bool { } // compatibleMetric returns the resulting metric for + and - operations. -func compatibleMetric(reg *MetricRegistry, a, b *Metric) *Metric { +func compatibleMetric(reg MetricReader, a, b *Metric) *Metric { return resultMetricForAdd([]*Metric{a, b}) } @@ -73,7 +73,7 @@ func compatibleMetric(reg *MetricRegistry, a, b *Metric) *Metric { // NOT by 1 (base units). // // Returns the converted float64 value in base units. -func convertToBase(reg *MetricRegistry, n StackValue, mode PrefixMode, resultMetric *Metric) (float64, error) { +func convertToBase(reg MetricReader, n StackValue, mode PrefixMode, resultMetric *Metric) (float64, error) { nv, ok := n.(NumericValue) if !ok { return 0, fmt.Errorf("convertToBase: value %q is not numeric", n) @@ -95,7 +95,7 @@ func convertToBase(reg *MetricRegistry, n StackValue, mode PrefixMode, resultMet } // convertFromBase converts a base-unit value back to the given metric. -func convertFromBase(reg *MetricRegistry, baseVal float64, m *Metric, mode PrefixMode) (float64, error) { +func convertFromBase(reg MetricReader, baseVal float64, m *Metric, mode PrefixMode) (float64, error) { if m == nil { var err error m, err = baseMetric(reg, "Cool") @@ -116,7 +116,7 @@ var multiplicationInference = map[[2]Category]string{ } // resultMetricForMul computes the resulting metric for multiplication. -func resultMetricForMul(reg *MetricRegistry, a, b *Metric) (*Metric, error) { +func resultMetricForMul(reg MetricReader, a, b *Metric) (*Metric, error) { if a == nil || a.Category == Universal { if b == nil { return baseMetric(reg, "Cool") @@ -141,7 +141,7 @@ var divisionInference = map[[2]Category]string{ } // resultMetricForDiv computes the resulting metric for division. -func resultMetricForDiv(reg *MetricRegistry, a, b *Metric) (*Metric, error) { +func resultMetricForDiv(reg MetricReader, a, b *Metric) (*Metric, error) { if a == nil && b == nil { return baseMetric(reg, "Cool") } @@ -179,7 +179,7 @@ func metricError(op string, a, b *Metric) error { } // coolMetric returns the Cool metric from the registry. -func coolMetric(reg *MetricRegistry) (*Metric, error) { +func coolMetric(reg MetricReader) (*Metric, error) { m, ok := reg.Find("Cool") if !ok { return nil, fmt.Errorf("metric registry missing Cool metric") @@ -188,7 +188,7 @@ func coolMetric(reg *MetricRegistry) (*Metric, error) { } // baseMetric looks up a base metric from the registry. -func baseMetric(reg *MetricRegistry, name string) (*Metric, error) { +func baseMetric(reg MetricReader, name string) (*Metric, error) { m, ok := reg.Find(name) if !ok { return nil, fmt.Errorf("metric registry missing base unit %q", name) diff --git a/internal/rpn/operations_metric_cmd.go b/internal/rpn/operations_metric_cmd.go index 255daed..370be98 100644 --- a/internal/rpn/operations_metric_cmd.go +++ b/internal/rpn/operations_metric_cmd.go @@ -150,11 +150,19 @@ func (o *Operations) CustomDefine(name string, factor float64, category string) Factor: func(PrefixMode) float64 { return factor }, IsCustom: true, } - reg.Register(m) + writer, ok := reg.(MetricWriter) + if !ok { + return fmt.Errorf("metric registry does not support write operations") + } + writer.Register(m) return nil } // CustomUndefine removes a custom metric. func (o *Operations) CustomUndefine(name string) error { - return o.metricRegistry.Unregister(name) + writer, ok := o.metricRegistry.(MetricWriter) + if !ok { + return fmt.Errorf("metric registry does not support write operations") + } + return writer.Unregister(name) } diff --git a/internal/rpn/rpn_state.go b/internal/rpn/rpn_state.go index adcf449..a42372a 100644 --- a/internal/rpn/rpn_state.go +++ b/internal/rpn/rpn_state.go @@ -22,7 +22,7 @@ type RPN struct { // NewRPN creates a new RPN parser and evaluator with the given variable store. // If no registry is provided, defaults to the global MetricRegistry. -func NewRPN(vars VariableStore, reg ...*MetricRegistry) *RPN { +func NewRPN(vars VariableStore, reg ...MetricReader) *RPN { consts := NewConstants() ops := NewOperations(vars, reg...) ops.SetMode(FloatMode) // Set default mode |
