goreg

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2025 License: MIT Imports: 11 Imported by: 1

README

📋 goreg

Go Reference Go Report Card Go GitHub license Made in Slovakia

goreg is a lightweight, thread-safe, and generic registry package for Go.

Features

  • Thread safety using mutexes
  • Go generics support
  • JSON and Gob serialization
  • Ordered registries for order-sensitive values
  • Easy-to-use methods for registration and retrieval

Use Cases

  • Application-wide configuration management
  • Plugin systems
  • Game modloaders and object registration

Installation

Run:

go get -u github.com/MatusOllah/goreg

Usage

package main

import (
    "fmt"

    "github.com/MatusOllah/goreg"
)

type Thing string

func main() {
    // Create a new empty registry
    reg := goreg.NewStandardRegistry[Thing]()

    // Register a thing
    reg.Register("door", Thing("Door"))

    // Retrieve the thing
    thing, ok := reg.Get("door")
    if ok {
        fmt.Println("Thing found:", thing)
    } else {
        fmt.Println("Thing not found")
    }

    // Unregister the thing
    reg.Unregister("door")
}
StandardRegistry[T] vs. OrderedRegistry[T]

There are 2 types of registries in goreg: The StandardRegistry[T] and the OrderedRegistry[T].

StandardRegistry[T] is a standard registry that uses a map under the hood. Output order is non-deterministic due to Go's map implementation. You can use this for most things that don't require specific order (e.g. users, clients).

OrderedRegistry[T] is however an ordered registry. It uses a slice of key-value pairs under the hood. You can use this for things that require specific order (e.g. game levels, chapters).

Example code:

package main

import (
    "fmt"

    "github.com/MatusOllah/goreg"
)

type Level struct {
    Name string
    // ...
}

func main() {
    stdReg := goreg.NewStandardRegistry[Level]()
    stdReg.Register("level1", Level{Name: "Level 1"})
    stdReg.Register("level2", Level{Name: "Level 2"})
    stdReg.Register("level3", Level{Name: "Level 3"})
    stdReg.Register("level4", Level{Name: "Level 4"})

    fmt.Println(goreg.Collect(stdReg)) // Output order is unpredictable due to Go maps, should print out in random order

    ordReg := goreg.NewOrderedRegistry[Level]()
    ordReg.Register("level1", Level{Name: "Level 1"})
    ordReg.Register("level2", Level{Name: "Level 2"})
    ordReg.Register("level3", Level{Name: "Level 3"})
    ordReg.Register("level4", Level{Name: "Level 4"})

    fmt.Println(goreg.Collect(ordReg)) // Should print out correctly in order
}

License

Licensed under the MIT License (see LICENSE)

Documentation

Overview

Package goreg implements a thread-safe, generic registry in Go.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Collect

func Collect[T any](reg Registry[T]) map[string]T

Collect collects key-value pairs from the registry into a new map and returns it.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewOrderedRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	theMap := goreg.Collect(reg)

	fmt.Println(theMap)

}
Output:

map[chair:Chair door:Door window:Window]

func Copy

func Copy[T any](dst, src Registry[T])

Copy copies all objects in src adding them to dst. When a ID in src is already present in dst, the value in dst will be overwritten by the value associated with the ID in src.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg1 := goreg.NewOrderedRegistry[Thing]()
	reg1.Register("door", Thing("Door"))
	reg1.Register("window", Thing("Window"))

	reg2 := goreg.NewOrderedRegistry[Thing]()
	reg2.Register("chair", Thing("Chair"))
	reg2.Register("microphone", Thing("Microphone"))

	goreg.Copy(reg1, reg2)

	fmt.Println(reg1)

}
Output:

[{door Door} {window Window} {chair Chair} {microphone Microphone}]

func Equal

func Equal[T comparable](reg1, reg2 Registry[T]) bool

Equal reports whether two registries contain the same objects. Objects are compared using ==.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg1 := goreg.NewOrderedRegistry[Thing]()
	reg1.Register("door", Thing("Door"))
	reg1.Register("window", Thing("Window"))

	reg2 := goreg.NewOrderedRegistry[Thing]()
	reg2.Register("door", Thing("Door"))
	reg2.Register("window", Thing("Window"))

	fmt.Println(goreg.Equal(reg1, reg2))

	reg2.Register("chair", Thing("Chair"))
	fmt.Println(goreg.Equal(reg1, reg2))

}
Output:

true
false

func EqualFunc

func EqualFunc[T1, T2 any](reg1 Registry[T1], reg2 Registry[T2], eq func(T1, T2) bool) bool

EqualFunc is like Equal, but compares values using eq. Objects are still compared with ==.

Types

type GetIndexRegistry added in v1.1.0

type GetIndexRegistry[T any] interface {
	Registry[T]

	// GetIndex returns the object under the index.
	GetIndex(i int) (obj T, ok bool)
}

A GetIndexRegistry is a registry with a GetIndex method.

type MustGetIndexRegistry added in v1.1.0

type MustGetIndexRegistry[T any] interface {
	Registry[T]

	// MustGetIndex returns the object under the index and logs error if not found.
	MustGetIndex(i int) T
}

A MustGetIndexRegistry is a registry with a MustGetIndex method.

type MustGetRegistry added in v1.1.0

type MustGetRegistry[T any] interface {
	Registry[T]

	// MustGet returns the object under the ID and logs error if not found.
	MustGet(id string) T
}

A MustGetRegistry is a registry with a MustGet method.

type OrderedRegistry

type OrderedRegistry[T any] struct {
	// contains filtered or unexported fields
}

OrderedRegistry is a ordered registry. It uses a slice under the hood.

func NewOrderedRegistry

func NewOrderedRegistry[T any]() *OrderedRegistry[T]

NewOrderedRegistry creates a new OrderedRegistry.

func (*OrderedRegistry[T]) Get

func (r *OrderedRegistry[T]) Get(id string) (obj T, ok bool)

Get returns the object under the ID.

func (*OrderedRegistry[T]) GetIndex

func (r *OrderedRegistry[T]) GetIndex(i int) (obj T, ok bool)

GetIndex returns the object under the index.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewOrderedRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	fmt.Println(reg.GetIndex(0))
	fmt.Println(reg.GetIndex(1))
	fmt.Println(reg.GetIndex(2))
	fmt.Println(reg.GetIndex(3))
	fmt.Println(reg.GetIndex(-1))

}
Output:

Door true
Window true
Chair true
 false
 false

func (*OrderedRegistry[T]) GobDecode

func (r *OrderedRegistry[T]) GobDecode(data []byte) error

GobDecode implements the encoding/gob.GobDecoder interface.

func (*OrderedRegistry[T]) GobEncode

func (r *OrderedRegistry[T]) GobEncode() ([]byte, error)

GobEncode implements the encoding/gob.GobEncoder interface.

func (*OrderedRegistry[T]) Iter

func (r *OrderedRegistry[T]) Iter() iter.Seq2[string, T]

Iter returns an iterator over key-value pairs. See the iter package documentation for more details.

Note that you should NOT call any other methods in the for loop. It will cause it to lock.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewOrderedRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	for id, obj := range reg.Iter() {
		fmt.Println(id, "=", obj)
	}

}
Output:

door = Door
window = Window
chair = Chair

func (*OrderedRegistry[T]) Len

func (r *OrderedRegistry[T]) Len() int

Len returns the number of items in the registry.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewOrderedRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	fmt.Println(reg.Len())

}
Output:

3

func (*OrderedRegistry[T]) MarshalJSON

func (r *OrderedRegistry[T]) MarshalJSON() ([]byte, error)

MarshalJSON implements the encoding/json.Marshaler interface.

func (*OrderedRegistry[T]) MustGet added in v1.1.0

func (r *OrderedRegistry[T]) MustGet(id string) T

MustGet returns the object under the ID and logs error if not found.

func (*OrderedRegistry[T]) MustGetIndex added in v1.1.0

func (r *OrderedRegistry[T]) MustGetIndex(i int) T

MustGetIndex returns the object under the index and logs error if not found.

func (*OrderedRegistry[T]) Register

func (r *OrderedRegistry[T]) Register(id string, obj T)

Register registers an object under the ID.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewOrderedRegistry[Thing]()
	reg.Register("door", Thing("Door"))

	fmt.Println(reg.Get("door"))

}
Output:

Door true

func (*OrderedRegistry[T]) Reset

func (r *OrderedRegistry[T]) Reset()

Reset wipes the registry.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewOrderedRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	fmt.Println(reg.Len())

	reg.Reset()

	fmt.Println(reg.Len())

}
Output:

3
0

func (*OrderedRegistry[T]) String

func (r *OrderedRegistry[T]) String() string

String returns a string representation of the registry.

func (*OrderedRegistry[T]) UnmarshalJSON

func (r *OrderedRegistry[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the encoding/json.Unmarshaler interface.

func (*OrderedRegistry[T]) Unregister

func (r *OrderedRegistry[T]) Unregister(id string)

Unregister unregisters an object under the ID.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewOrderedRegistry[Thing]()
	reg.Register("door", Thing("Door"))

	fmt.Println(reg.Get("door"))

	reg.Unregister("door")
	fmt.Println(reg.Get("door"))

}
Output:

Door true
 false

type Registry

type Registry[T any] interface {
	// Register registers an object under the ID.
	Register(id string, obj T)

	// Unregister unregisters an object under the ID.
	Unregister(id string)

	// Get returns the object under the ID.
	Get(id string) (obj T, ok bool)

	// Len returns the number of items in the registry.
	Len() int

	// Reset wipes the registry.
	Reset()

	// Iter returns an iterator over key-value pairs. See the [iter] package documentation for more details.
	Iter() iter.Seq2[string, T]

	fmt.Stringer
}

Registry represents a generic registry.

type StandardRegistry

type StandardRegistry[T any] struct {
	// contains filtered or unexported fields
}

StandardRegistry is a standard registry. It uses a map under the hood.

func NewStandardRegistry

func NewStandardRegistry[T any]() *StandardRegistry[T]

NewStandardRegistry creates a new StandardRegistry.

func (*StandardRegistry[T]) Get

func (r *StandardRegistry[T]) Get(id string) (obj T, ok bool)

Get returns the object under the ID.

func (*StandardRegistry[T]) GobDecode

func (r *StandardRegistry[T]) GobDecode(data []byte) error

GobDecode implements the encoding/gob.GobDecoder interface.

func (*StandardRegistry[T]) GobEncode

func (r *StandardRegistry[T]) GobEncode() ([]byte, error)

GobEncode implements the encoding/gob.GobEncoder interface.

func (*StandardRegistry[T]) Iter

func (r *StandardRegistry[T]) Iter() iter.Seq2[string, T]

Iter returns an iterator over key-value pairs. See the iter package documentation for more details.

Note that you should NOT call any other methods in the for loop. It will cause it to lock.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewStandardRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	for id, obj := range reg.Iter() {
		if id == "door" {
			fmt.Println("found", id, "=", obj)
		}
	}

}
Output:

found door = Door

func (*StandardRegistry[T]) Len

func (r *StandardRegistry[T]) Len() int

Len returns the number of items in the registry.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewStandardRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	fmt.Println(reg.Len())

}
Output:

3

func (*StandardRegistry[T]) MarshalJSON

func (r *StandardRegistry[T]) MarshalJSON() ([]byte, error)

MarshalJSON implements the encoding/json.Marshaler interface.

func (*StandardRegistry[T]) MustGet added in v1.1.0

func (r *StandardRegistry[T]) MustGet(id string) T

MustGet returns the object under the ID and logs error if not found.

func (*StandardRegistry[T]) Register

func (r *StandardRegistry[T]) Register(id string, obj T)

Register registers an object under the ID.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewStandardRegistry[Thing]()
	reg.Register("door", Thing("Door"))

	fmt.Println(reg.Get("door"))

}
Output:

Door true

func (*StandardRegistry[T]) Reset

func (r *StandardRegistry[T]) Reset()

Reset wipes the registry.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewStandardRegistry[Thing]()
	reg.Register("door", Thing("Door"))
	reg.Register("window", Thing("Window"))
	reg.Register("chair", Thing("Chair"))

	fmt.Println(reg.Len())

	reg.Reset()

	fmt.Println(reg.Len())

}
Output:

3
0

func (*StandardRegistry[T]) String

func (r *StandardRegistry[T]) String() string

String returns a string representation of the registry.

func (*StandardRegistry[T]) UnmarshalJSON

func (r *StandardRegistry[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the encoding/json.Unmarshaler interface.

func (*StandardRegistry[T]) Unregister

func (r *StandardRegistry[T]) Unregister(id string)

Unregister unregisters an object under the ID.

Example
package main

import (
	"fmt"

	"github.com/MatusOllah/goreg"
)

func main() {
	type Thing string

	reg := goreg.NewStandardRegistry[Thing]()
	reg.Register("door", Thing("Door"))

	fmt.Println(reg.Get("door"))

	reg.Unregister("door")
	fmt.Println(reg.Get("door"))

}
Output:

Door true
 false

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL