87 lines
2.7 KiB
Go
87 lines
2.7 KiB
Go
package transcode
|
||
|
||
import (
|
||
"fmt"
|
||
"sort"
|
||
"sync"
|
||
)
|
||
|
||
// Registry 承载「哪些 源→目标 可用」(design/25 §1.3.2 第一层)。它是**包内**的
|
||
// 编解码器注册表,与全局能力注册表(internal/capability/registry)是两件事:
|
||
// 后者表达「agent 可选用的能力 + 门控策略」,前者表达「本能力认识哪几条路」。
|
||
//
|
||
// 新增一种格式 = 往这里多一个注册项(见 codecs.go 的 DefaultCodecs);
|
||
// 并发安全。
|
||
type Registry struct {
|
||
mu sync.RWMutex
|
||
codecs map[route]Codec
|
||
}
|
||
|
||
// route 是「源→目标」这一对,作注册表的键。用结构体而非字符串拼接:拼接会让
|
||
// 格式名里出现分隔符时产生歧义(`a->b` 与 `a-` + `>b`)。
|
||
type route struct {
|
||
from Format
|
||
to Format
|
||
}
|
||
|
||
// NewRegistry 返回一个空且并发安全的编解码器注册表。
|
||
func NewRegistry() *Registry {
|
||
return &Registry{codecs: make(map[route]Codec)}
|
||
}
|
||
|
||
// Register 注册一条转换路。nil、源/目标为空、源等于目标都返回 ErrInvalidCodec;
|
||
// 同一对重复注册返回 ErrDuplicate。
|
||
func (r *Registry) Register(c Codec) error {
|
||
if c == nil {
|
||
return fmt.Errorf("transcode: register codec: %w: nil codec", ErrInvalidCodec)
|
||
}
|
||
from, to := c.From(), c.To()
|
||
if from == "" || to == "" {
|
||
return fmt.Errorf("transcode: register codec %q -> %q: %w: empty format", from, to, ErrInvalidCodec)
|
||
}
|
||
if from == to {
|
||
return fmt.Errorf("transcode: register codec %q -> %q: %w: identity route", from, to, ErrInvalidCodec)
|
||
}
|
||
r.mu.Lock()
|
||
defer r.mu.Unlock()
|
||
key := route{from: from, to: to}
|
||
if _, exists := r.codecs[key]; exists {
|
||
return fmt.Errorf("transcode: register codec %q -> %q: %w", from, to, ErrDuplicate)
|
||
}
|
||
r.codecs[key] = c
|
||
return nil
|
||
}
|
||
|
||
// Lookup 返回 from→to 这条路上的编解码器。没有这条路时 ok 为 false。
|
||
func (r *Registry) Lookup(from, to Format) (Codec, bool) {
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
c, ok := r.codecs[route{from: from, to: to}]
|
||
return c, ok
|
||
}
|
||
|
||
// Formats 返回当前注册涉及的全部格式(源与目标去重后的并集,已排序)。
|
||
// 它是「发现」面:调用方据此知道本能力认识哪些格式名。
|
||
func (r *Registry) Formats() []Format {
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
seen := make(map[Format]struct{}, len(r.codecs)*2)
|
||
for key := range r.codecs {
|
||
seen[key.from] = struct{}{}
|
||
seen[key.to] = struct{}{}
|
||
}
|
||
out := make([]Format, 0, len(seen))
|
||
for f := range seen {
|
||
out = append(out, f)
|
||
}
|
||
sort.Slice(out, func(i, j int) bool { return out[i] < out[j] })
|
||
return out
|
||
}
|
||
|
||
// Len 返回已注册的「源→目标」路数。供启动期自检与测试断言使用。
|
||
func (r *Registry) Len() int {
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
return len(r.codecs)
|
||
}
|