// Copyright 2024 Matthew Rich . All rights reserved. package types import ( "errors" "fmt" "net/url" "strings" "path/filepath" ) var ( ErrUnknownType = errors.New("Unknown type") ) //type Name string //`json:"type"` type Factory[Product any] func(*url.URL) Product type RegistryTypeMap[Product any] map[string]Factory[Product] type Types[Product any] struct { registry RegistryTypeMap[Product] } func New[Product any]() *Types[Product] { return &Types[Product]{registry: make(map[string]Factory[Product])} } func (t *Types[Product]) Register(names []string, factory Factory[Product]) { for _,name := range names { t.registry[name] = factory } } func (t *Types[Product]) FromExtension(path string) (Factory[Product], error) { elements := strings.Split(path, ".") numberOfElements := len(elements) if numberOfElements > 2 { if src := t.Get(strings.Join(elements[numberOfElements - 2: numberOfElements - 1], ".")); src != nil { return src, nil } } if src := t.Get(elements[numberOfElements - 1]); src != nil { return src, nil } return nil, fmt.Errorf("%w: %s", ErrUnknownType, path) } func (t *Types[Product]) New(uri string) (result Product, err error) { u, e := url.Parse(uri) if u == nil || e != nil { err = fmt.Errorf("%w: %s", ErrUnknownType, e) return } if u.Scheme == "" { u.Scheme = "file" } path := filepath.Join(u.Hostname(), u.Path) if d, lookupErr := t.FromExtension(path); d != nil { return d(u), lookupErr } if r, ok := t.registry[u.Scheme]; ok { return r(u), nil } err = fmt.Errorf("%w: %s", ErrUnknownType, u.Scheme) return } func (t *Types[Product]) Has(typename string) bool { if _, ok := t.registry[typename]; ok { return true } return false } func (t *Types[Product]) Get(typename string) Factory[Product] { if d, ok := t.registry[typename]; ok { return d } return nil } /* func (n *Name) UnmarshalJSON(b []byte) error { TypeName := strings.Trim(string(b), "\"") if SourceTypes.Has(TypeName) { *n = TypeName(TypeName) return nil } return fmt.Errorf("%w: %s", ErrUnknownType, TypeName) } */