Documentation
¶
Overview ¶
Package state provides batch update support for reactive primitives. Note: In a concurrent Go web server, global batching (as in Svelte) shares state across requests. Batching is a pass-through in this implementation to ensure safety.
Package state provides Derived[T] for computed/derived reactive state. Derived values automatically recalculate when their dependencies change.
Package state provides Effect for reactive side effects. Effects run when their dependencies change, similar to Svelte's $effect rune.
Package state provides build-time state pruning for GoSPA applications. This reduces bundle size by eliminating unused state at build time.
Package state provides Svelte rune-like reactive primitives for Go. Rune[T] is the base reactive primitive that holds a value and notifies subscribers on changes.
Package state provides serialization utilities for reactive state. These helpers convert state to JSON for client transmission.
Index ¶
- func Batch(fn func())
- func BatchError(fn func() error) error
- func BatchResult[T any](fn func() T) T
- func CalculateTreeSize(tree *StateTree) int
- func SerializePrunedState(state map[string]any, usedPaths map[string]bool) map[string]any
- func SerializeState(runes map[string]interface{}) ([]byte, error)
- type CleanupFunc
- type Derived
- func Derived2[A, B, T any](a *Rune[A], b *Rune[B], combine func(A, B) T) *Derived[T]
- func Derived3[A, B, C, T any](a *Rune[A], b *Rune[B], c *Rune[C], combine func(A, B, C) T) *Derived[T]
- func DerivedFrom[T any](compute func() T, observables ...Observable) *Derived[T]
- func NewDerived[T any](compute func() T) *Derived[T]
- func (d *Derived[T]) DependOn(o Observable)
- func (d *Derived[T]) Dispose()
- func (d *Derived[T]) Get() T
- func (d *Derived[T]) GetAny() any
- func (d *Derived[T]) ID() string
- func (d *Derived[T]) MarshalJSON() ([]byte, error)
- func (d *Derived[T]) Subscribe(fn Subscriber[T]) Unsubscribe
- func (d *Derived[T]) SubscribeAny(fn func(any)) Unsubscribe
- type Effect
- type EffectFn
- type Observable
- type PruningConfig
- type PruningReport
- type Rune
- func (r *Rune[T]) Get() T
- func (r *Rune[T]) GetAny() any
- func (r *Rune[T]) ID() string
- func (r *Rune[T]) MarshalJSON() ([]byte, error)
- func (r *Rune[T]) Set(value T)
- func (r *Rune[T]) SetAny(value any) error
- func (r *Rune[T]) Subscribe(fn Subscriber[T]) Unsubscribe
- func (r *Rune[T]) SubscribeAny(fn func(any)) Unsubscribe
- func (r *Rune[T]) Update(fn func(T) T)
- type Serializable
- type Settable
- type StateDiff
- type StateMap
- func (sm *StateMap) Add(name string, obs Observable) *StateMap
- func (sm *StateMap) AddAny(name string, value interface{}) *StateMap
- func (sm *StateMap) ForEach(fn func(key string, value any))
- func (sm *StateMap) Get(name string) (Observable, bool)
- func (sm *StateMap) MarshalJSON() ([]byte, error)
- func (sm *StateMap) ToJSON() (string, error)
- func (sm *StateMap) ToMap() map[string]any
- type StateMessage
- func NewErrorMessage(componentID, errMsg string) *StateMessage
- func NewInitMessage(componentID string, state interface{}) *StateMessage
- func NewSyncMessage(componentID string, state interface{}) *StateMessage
- func NewUpdateMessage(componentID, key string, value interface{}) *StateMessage
- func ParseMessage(data []byte) (*StateMessage, error)
- type StatePruner
- type StateSnapshot
- type StateTree
- type StateUsage
- type StateValidator
- type Subscriber
- type Unsubscribe
- type Validator
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Batch ¶
func Batch(fn func())
Batch executes the given function. For server safety, it no longer defers notifications globally.
func BatchError ¶
BatchError allows batching with error return
func BatchResult ¶
func BatchResult[T any](fn func() T) T
BatchResult allows batching with a return value
func CalculateTreeSize ¶
CalculateTreeSize calculates the estimated size of a state tree.
func SerializePrunedState ¶
SerializePrunedState serializes only the used portions of state.
func SerializeState ¶
SerializeState serializes multiple runes into a JSON object
Types ¶
type Derived ¶
type Derived[T any] struct { // contains filtered or unexported fields }
Derived is a computed value that automatically updates when dependencies change. Similar to Svelte's $derived rune, it recalculates its value based on a compute function and notifies subscribers when the computed value changes.
func Derived3 ¶
func Derived3[A, B, C, T any](a *Rune[A], b *Rune[B], c *Rune[C], combine func(A, B, C) T) *Derived[T]
Derived3 creates a derived value from three runes with a combine function.
func DerivedFrom ¶
func DerivedFrom[T any](compute func() T, observables ...Observable) *Derived[T]
DerivedFrom creates a derived value that depends on one or more observables. This is a convenience function that automatically sets up dependencies.
Example:
count := state.NewRune(5)
doubled := state.DerivedFrom(func() int {
return count.Get() * 2
}, count)
func NewDerived ¶
NewDerived creates a new derived value from a compute function. The compute function is called immediately to get the initial value.
Example:
count := state.NewRune(5)
doubled := state.NewDerived(func() int {
return count.Get() * 2
})
func (*Derived[T]) DependOn ¶
func (d *Derived[T]) DependOn(o Observable)
DependOn adds an observable as a dependency of this derived value. When the observable changes, this derived value will be marked dirty.
Example:
count := state.NewRune(5)
doubled := state.NewDerived(func() int {
return count.Get() * 2
})
doubled.DependOn(count)
func (*Derived[T]) Dispose ¶
func (d *Derived[T]) Dispose()
Dispose cleans up all subscriptions to dependencies
func (*Derived[T]) Get ¶
func (d *Derived[T]) Get() T
Get returns the current computed value. If dependencies have changed, it recomputes first.
func (*Derived[T]) GetAny ¶
GetAny returns the current value of the derivative as an interface{}. This implements the Observable interface.
func (*Derived[T]) MarshalJSON ¶
MarshalJSON implements json.Marshaler for serialization
func (*Derived[T]) Subscribe ¶
func (d *Derived[T]) Subscribe(fn Subscriber[T]) Unsubscribe
Subscribe registers a callback for when the derived value changes. Returns an unsubscribe function.
func (*Derived[T]) SubscribeAny ¶
func (d *Derived[T]) SubscribeAny(fn func(any)) Unsubscribe
SubscribeAny registers a type-erased callback. This implements the Observable interface.
type Effect ¶
type Effect struct {
// contains filtered or unexported fields
}
Effect represents a reactive side effect that runs when dependencies change.
func EffectOn ¶
func EffectOn(fn EffectFn, observables ...Observable) *Effect
EffectOn creates an effect that depends on one or more observables. This is a convenience function that automatically sets up dependencies.
Example:
count := state.NewRune(0)
effect := state.EffectOn(func() state.CleanupFunc {
fmt.Println("Count is:", count.Get())
return nil
}, count)
defer effect.Dispose()
func NewEffect ¶
NewEffect creates a new effect that runs the given function. The function can return a cleanup function that runs before the next execution or when the effect is disposed.
Example:
count := state.NewRune(0)
effect := state.NewEffect(func() state.CleanupFunc {
fmt.Println("Count is:", count.Get())
return func() {
fmt.Println("Cleaning up")
}
})
defer effect.Dispose()
func (*Effect) DependOn ¶
func (e *Effect) DependOn(o Observable)
DependOn adds an observable as a dependency of this effect. When the observable changes, the effect will re-run.
func (*Effect) Dispose ¶
func (e *Effect) Dispose()
Dispose permanently stops the effect and cleans up resources
type Observable ¶
type Observable interface {
SubscribeAny(func(any)) Unsubscribe
GetAny() any
}
Observable provides a type-erased interface for state primitives. This allows storing mixed-type Runes in a single collection.
type PruningConfig ¶
type PruningConfig struct {
// RootDir is the project root directory.
RootDir string `json:"rootDir"`
// OutputDir is where pruned state files are written.
OutputDir string `json:"outputDir"`
// ExcludePatterns are regex patterns for files to exclude.
ExcludePatterns []string `json:"excludePatterns"`
// IncludePatterns are regex patterns for files to include.
IncludePatterns []string `json:"includePatterns"`
// KeepUnused keeps state even if not directly referenced.
KeepUnused bool `json:"keepUnused"`
// Aggressive enables more aggressive pruning.
Aggressive bool `json:"aggressive"`
// ReportFile is where to write the pruning report.
ReportFile string `json:"reportFile"`
}
PruningConfig configures state pruning behavior.
func DefaultPruningConfig ¶
func DefaultPruningConfig() PruningConfig
DefaultPruningConfig returns sensible defaults.
type PruningReport ¶
type PruningReport struct {
TotalStateVars int `json:"totalStateVars"`
UsedStateVars int `json:"usedStateVars"`
PrunedStateVars int `json:"prunedStateVars"`
EstimatedSavings int `json:"estimatedSavings"`
StateUsage map[string]StateUsage `json:"stateUsage"`
PrunedFiles []string `json:"prunedFiles"`
Errors []string `json:"errors,omitempty"`
}
PruningReport contains the results of state analysis.
func AnalyzeState ¶
func AnalyzeState(config PruningConfig) (*PruningReport, error)
AnalyzeState is a convenience function for state analysis.
func PruneState ¶
func PruneState(config PruningConfig) (*PruningReport, error)
PruneState is a convenience function for state pruning.
type Rune ¶
type Rune[T any] struct { // contains filtered or unexported fields }
Rune is the base reactive primitive, similar to Svelte's $state rune. It holds a value of type T and notifies all subscribers when the value changes.
func NewRune ¶
NewRune creates a new Rune with the given initial value. This is equivalent to Svelte's $state rune.
Example:
count := state.NewRune(0)
name := state.NewRune("hello")
func (*Rune[T]) Get ¶
func (r *Rune[T]) Get() T
Get returns the current value of the rune. This is thread-safe and can be called concurrently.
func (*Rune[T]) GetAny ¶
GetAny returns the current value of the rune as an interface{}. This implements the Observable interface.
func (*Rune[T]) MarshalJSON ¶
MarshalJSON implements json.Marshaler for serialization to client.
func (*Rune[T]) Set ¶
func (r *Rune[T]) Set(value T)
Set updates the rune's value and notifies all subscribers. If the value is being batched, notification is deferred until the batch completes. This is thread-safe and can be called concurrently.
func (*Rune[T]) SetAny ¶
SetAny updates the rune's value from an interface{}. This implements the Settable interface.
func (*Rune[T]) Subscribe ¶
func (r *Rune[T]) Subscribe(fn Subscriber[T]) Unsubscribe
Subscribe registers a callback that will be called whenever the value changes. Returns an Unsubscribe function to remove the subscription.
Example:
unsub := count.Subscribe(func(v int) {
fmt.Println("Count changed to:", v)
})
defer unsub()
func (*Rune[T]) SubscribeAny ¶
func (r *Rune[T]) SubscribeAny(fn func(any)) Unsubscribe
SubscribeAny registers a type-erased callback. This implements the Observable interface.
type Serializable ¶
Serializable represents a value that can be serialized to JSON
type Settable ¶
type Settable interface {
Observable
SetAny(any) error
}
Settable extends Observable for types that can be updated.
type StateDiff ¶
type StateDiff struct {
ComponentID string `json:"componentId"`
Key string `json:"key"`
OldValue interface{} `json:"oldValue,omitempty"`
NewValue interface{} `json:"newValue"`
Timestamp int64 `json:"timestamp"`
}
StateDiff represents a change in state
func NewStateDiff ¶
NewStateDiff creates a new state diff
func (*StateDiff) MarshalJSON ¶
MarshalJSON serializes the diff to JSON
type StateMap ¶
type StateMap struct {
OnChange func(key string, value any) // Callback invoked when a state variable changes
// contains filtered or unexported fields
}
StateMap is a collection of generic observables for component state
func (*StateMap) Add ¶
func (sm *StateMap) Add(name string, obs Observable) *StateMap
Add adds an observable to the state collection
func (*StateMap) Get ¶
func (sm *StateMap) Get(name string) (Observable, bool)
Get retrieves an observable by name
func (*StateMap) MarshalJSON ¶
MarshalJSON serializes the state map to JSON
type StateMessage ¶
type StateMessage struct {
Type string `json:"type"` // "init", "update", "sync", "error"
ComponentID string `json:"componentId,omitempty"`
Key string `json:"key,omitempty"`
Value interface{} `json:"value,omitempty"`
State interface{} `json:"state,omitempty"`
Error string `json:"error,omitempty"`
Timestamp int64 `json:"timestamp"`
}
StateMessage represents a message sent between server and client
func NewErrorMessage ¶
func NewErrorMessage(componentID, errMsg string) *StateMessage
NewErrorMessage creates an error message
func NewInitMessage ¶
func NewInitMessage(componentID string, state interface{}) *StateMessage
NewInitMessage creates an initialization message
func NewSyncMessage ¶
func NewSyncMessage(componentID string, state interface{}) *StateMessage
NewSyncMessage creates a sync message
func NewUpdateMessage ¶
func NewUpdateMessage(componentID, key string, value interface{}) *StateMessage
NewUpdateMessage creates an update message
func ParseMessage ¶
func ParseMessage(data []byte) (*StateMessage, error)
ParseMessage parses a JSON message
func (*StateMessage) MarshalJSON ¶
func (m *StateMessage) MarshalJSON() ([]byte, error)
MarshalJSON serializes the message to JSON
type StatePruner ¶
type StatePruner struct {
// contains filtered or unexported fields
}
StatePruner analyzes and prunes unused state.
func NewStatePruner ¶
func NewStatePruner(config PruningConfig) *StatePruner
NewStatePruner creates a new state pruner.
func (*StatePruner) Analyze ¶
func (sp *StatePruner) Analyze() (*PruningReport, error)
Analyze scans the codebase for state usage.
func (*StatePruner) GetReport ¶
func (sp *StatePruner) GetReport() *PruningReport
GetReport returns the current pruning report.
func (*StatePruner) Prune ¶
func (sp *StatePruner) Prune() (*PruningReport, error)
Prune removes unused state from the codebase.
func (*StatePruner) WriteReport ¶
func (sp *StatePruner) WriteReport(path string) error
WriteReport writes the pruning report to a file.
type StateSnapshot ¶
type StateSnapshot struct {
ComponentID string `json:"componentId"`
State map[string]interface{} `json:"state"`
Timestamp int64 `json:"timestamp"`
}
StateSnapshot represents a snapshot of component state at a point in time
func NewSnapshot ¶
func NewSnapshot(componentID string, state map[string]interface{}) *StateSnapshot
NewSnapshot creates a new state snapshot
func (*StateSnapshot) MarshalJSON ¶
func (s *StateSnapshot) MarshalJSON() ([]byte, error)
MarshalJSON serializes the snapshot to JSON
type StateTree ¶
type StateTree struct {
Name string `json:"name"`
Type string `json:"type"`
Size int `json:"size"`
Children map[string]*StateTree `json:"children,omitempty"`
Used bool `json:"used"`
Path string `json:"path"`
}
StateTree represents a hierarchical state structure for analysis.
func BuildStateTree ¶
BuildStateTree builds a hierarchical representation of state.
type StateUsage ¶
type StateUsage struct {
Name string `json:"name"`
File string `json:"file"`
Line int `json:"line"`
Type string `json:"type"`
References []string `json:"references,omitempty"`
IsExported bool `json:"isExported"`
IsUsed bool `json:"isUsed"`
CanPrune bool `json:"canPrune"`
}
StateUsage represents how a state variable is used.
type StateValidator ¶
type StateValidator struct {
// contains filtered or unexported fields
}
StateValidator validates state values
func NewStateValidator ¶
func NewStateValidator() *StateValidator
NewStateValidator creates a new state validator
func (*StateValidator) AddValidator ¶
func (sv *StateValidator) AddValidator(key string, v Validator)
AddValidator adds a validator for a key
func (*StateValidator) Validate ¶
func (sv *StateValidator) Validate(key string, value interface{}) error
Validate validates a value for a key
func (*StateValidator) ValidateAll ¶
func (sv *StateValidator) ValidateAll(values map[string]interface{}) error
ValidateAll validates all values in a map
type Subscriber ¶
type Subscriber[T any] func(T)
Subscriber is a callback function that receives value updates.
type Unsubscribe ¶
type Unsubscribe func()
Unsubscribe is a function returned by Subscribe to remove the subscription.
func Watch ¶
func Watch[T any](r *Rune[T], callback func(T)) Unsubscribe
Watch creates an effect that watches a single rune and calls a callback with its value.
Example:
count := state.NewRune(0)
unsub := state.Watch(count, func(v int) {
fmt.Println("Count changed to:", v)
})
defer unsub()