osync

package module
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2026 License: MIT Imports: 7 Imported by: 0

README

osync

osync is a Go library designed to provide thread-safe data structures and utilities for concurrent programming. Built with simplicity and performance in mind, osync leverages Mutex, RWMutex and Atomic to ensure safe access to shared resources.

Features

  • Thread-safe collections: Protects against race conditions with minimal overhead.
  • Observable values: Allows observing changes to a value.
  • Event handling: Provides synchronization primitives for coordinating tasks.
  • Simple API: Focuses on ease of use while offering powerful concurrency control.
  • Generic support: Utilizes Go generics to create versatile and reusable data structures.

Installation

To install osync, use go get:

go get github.com/eos175/osync

Usage

Set Example

Here's an example of how to use the Set provided by osync:

package main

import (
	"fmt"

	"github.com/eos175/osync"
)

func main() {
	set := osync.NewSet[int]()

	set.Add(1)
	set.Add(2)
	set.Add(3)

	fmt.Println("Set has 2:", set.Has(2)) // Output: Set has 2: true
	fmt.Println("Set length:", set.Len()) // Output: Set length: 3

	set.Delete(2)

	fmt.Println("Set has 2:", set.Has(2)) // Output: Set has 2: false

	// go1.23
	fmt.Println("Set contents:")
	for key := range set.Iterator() {
		fmt.Println(key)
	}
}
Observable Example

Here's an example of how to use the Observable provided by osync:

package main

import (
	"fmt"
	"time"

	"github.com/eos175/osync"
)

func main() {
	obs := osync.NewObservable[int](0)
	defer obs.Close()

	// Subscribe to changes. This returns a channel and an unsubscribe function.
	ch, unsubscribe := obs.Subscribe()
	// It's important to call unsubscribe when done to avoid leaks.
	defer unsubscribe()

	// This goroutine will stop the subscription after 5 seconds.
	go func() {
		time.Sleep(5 * time.Second)
		fmt.Println("Unsubscribing...")
		unsubscribe()
	}()

	// This goroutine updates the observable value.
	go func() {
		for i := 1; ; i++ {
			// This Set will be missed if it happens after unsubscribe.
			obs.Set(i * i)
			time.Sleep(1 * time.Second)
		}
	}()

	// Print updates received from the observable.
	// The loop will end when the channel is closed by the unsubscribe call.
	for value := range ch {
		fmt.Println("Received value:", value)
	}

	fmt.Println("Subscription ended.")
}
Event Example

Here's an example of how to use the Event provided by osync:

package main

import (
	"fmt"
	"time"

	"github.com/eos175/osync"
)

func main() {
	event := osync.NewEvent()

	go func() {
		// Wait for the event to be set
		fmt.Println("Waiting for event to be set...")
		event.Wait()
		fmt.Println("Event is set!")
	}()

	go func() {
		// Simulate some work before setting the event
		time.Sleep(2 * time.Second)
		fmt.Println("Setting event...")
		event.Set()
	}()

	// Wait for the event to be set
	time.Sleep(3 * time.Second)
}
Control Utilities

The control package provides utilities for controlling function execution flow.

Debouncer

Executes a function only after a specified duration has passed without new calls.

package main

import (
	"fmt"
	"time"

	"github.com/eos175/osync/control"
)

func main() {
	debouncer := control.NewDebouncer(100 * time.Millisecond)

	// Will execute only the last call after 100ms
	debouncer(func() { fmt.Println("1") })
	debouncer(func() { fmt.Println("2") })
	debouncer(func() { fmt.Println("3") }) // Only this one runs

	time.Sleep(200 * time.Millisecond)
}
Throttle

Ensures a function is not executed more frequently than a specified interval.

package main

import (
	"fmt"
	"time"

	"github.com/eos175/osync/control"
)

func main() {
	throttle := control.NewThrottle(100 * time.Millisecond)

	// First call runs immediately
	throttle(func() { fmt.Println("Run 1") })

	// This call is skipped because it's too soon
	throttle(func() { fmt.Println("Run 2") })

	time.Sleep(150 * time.Millisecond)
	// This call runs
	throttle(func() { fmt.Println("Run 3") })
}
Scheduled Periodic Tasks

To schedule a task to run periodically starting at a specific time (e.g., daily backups), you can combine NextDailyAt with IntervalAt.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/eos175/osync/control"
)

func main() {
	ctx := context.Background()

	// Calculate the next occurrence of 03:00:00 AM (local time)
	start := control.NextDailyAt(time.Now(), 3, 0, 0)

	// To use a specific timezone (e.g., UTC):
	// start := control.NextDailyAt(time.Now().In(time.UTC), 3, 0, 0)

	// Schedule the task to run daily starting at 'start'
	control.IntervalAt(ctx, start, 24*time.Hour, func() {
		fmt.Println("Starting daily backup...")
	})

	// Block main process
	select {}
}
IntervalAt

Execute a task at a regular interval, starting at a specific future time.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/eos175/osync/control"
)

func main() {
	ctx := context.Background()
	start := time.Now().Add(1 * time.Hour) // Start in 1 hour

	control.IntervalAt(ctx, start, 30*time.Minute, func() {
		fmt.Println("Running task...")
	})
}

Documentation

The full documentation is available on pkg.go.dev.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Event

type Event struct {
	// contains filtered or unexported fields
}

Event struct containing a state and a pointer to a channel

func NewEvent

func NewEvent() *Event

NewEvent initializes and returns a new Event instance

func (*Event) Clear

func (e *Event) Clear()

Clear the state of the event

func (*Event) IsSet

func (e *Event) IsSet() bool

IsSet checks if the event is set

func (*Event) Set

func (e *Event) Set()

Set the event and broadcast if it's newly set

func (*Event) Wait

func (e *Event) Wait()

Wait until the event is set

func (*Event) WaitTimeout

func (e *Event) WaitTimeout(timeout time.Duration) bool

WaitTimeout waits for the event to be set until the timeout

type Map

type Map[K comparable, T any] struct {
	// contains filtered or unexported fields
}

func NewMap

func NewMap[K comparable, T any]() *Map[K, T]

func (*Map[K, T]) ChangeKey

func (s *Map[K, T]) ChangeKey(key, new_key K) (T, bool)

func (*Map[K, T]) Clear

func (s *Map[K, T]) Clear()

func (*Map[K, T]) Clone

func (s *Map[K, T]) Clone() *Map[K, T]

func (*Map[K, T]) Delete

func (s *Map[K, T]) Delete(key K)

func (*Map[K, T]) DeleteIf added in v0.5.0

func (s *Map[K, T]) DeleteIf(key K, condition func(T) bool)

func (*Map[K, T]) ForEach

func (s *Map[K, T]) ForEach(fn func(key K, value T) bool)

func (*Map[K, T]) ForEachSnapshot added in v0.2.0

func (s *Map[K, T]) ForEachSnapshot(fn func(key K, value T) bool)

func (*Map[K, T]) Get

func (s *Map[K, T]) Get(key K) (T, bool)

func (*Map[K, T]) GetOrSet

func (s *Map[K, T]) GetOrSet(key K, valueFn func() T) (actual T, loaded bool)

func (*Map[K, T]) Iterator added in v0.2.0

func (s *Map[K, T]) Iterator() iter.Seq2[K, T]

func (*Map[K, T]) Len

func (s *Map[K, T]) Len() int

func (*Map[K, T]) Pop

func (s *Map[K, T]) Pop(key K) (T, bool)

func (*Map[K, T]) PopIf added in v0.5.0

func (s *Map[K, T]) PopIf(key K, condition func(T) bool) (T, bool)

func (*Map[K, T]) Set

func (s *Map[K, T]) Set(key K, value T)

func (*Map[K, T]) SnapshotIterator added in v0.2.0

func (s *Map[K, T]) SnapshotIterator() iter.Seq2[K, T]

SnapshotIterator returns an iterator over an immutable copy (snapshot) of the map. This allows safe iteration without blocking concurrent access to the original map.

func (*Map[K, T]) UpdateIf added in v0.5.2

func (s *Map[K, T]) UpdateIf(key K, condition func(T) bool, updateFn func(T) T) bool

type Observable

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

Observable is a generic structure that represents a value that can be observed.

func NewObservable

func NewObservable[T any](initialValue T) *Observable[T]

NewObservable creates a new Observable with an initial value.

func (*Observable[T]) Close added in v0.5.1

func (o *Observable[T]) Close()

Close terminates all subscriptions and cleans up the observable's resources.

func (*Observable[T]) Get

func (o *Observable[T]) Get() T

Get returns the current value of the observable.

func (*Observable[T]) Len

func (o *Observable[T]) Len() int

Len returns the number of observers currently subscribed.

func (*Observable[T]) Set

func (o *Observable[T]) Set(value T)

Set updates the value of the observable and notifies all observers atomically.

func (*Observable[T]) Subscribe

func (o *Observable[T]) Subscribe() (<-chan T, func())

Subscribe allows an observer to receive notifications. It returns a channel for receiving values and an unsubscribe function that must be called to clean up the subscription. The current value is sent to the subscriber upon subscription.

type Set

type Set[T comparable] struct {
	// contains filtered or unexported fields
}

func NewSet

func NewSet[T comparable]() *Set[T]

func (*Set[T]) Add

func (s *Set[T]) Add(key T) bool

Adds a key to the set. Returns `true` if the key was added, or `false` if it already existed.

func (*Set[T]) Clear

func (s *Set[T]) Clear()

Removes all keys from the set.

func (*Set[T]) Clone

func (s *Set[T]) Clone() *Set[T]

Returns a shallow copy of the set.

func (*Set[T]) Delete

func (s *Set[T]) Delete(key T)

Removes a key from the set.

func (*Set[T]) DeleteIf added in v0.5.1

func (s *Set[T]) DeleteIf(key T, condition func(key T) bool)

DeleteIf deletes the given key from the set, but only if the key exists and satisfies the provided condition. The operation is atomic.

func (*Set[T]) ForEach

func (s *Set[T]) ForEach(fn func(key T) bool)

Iterates over all keys in the set, applying the provided function.

func (*Set[T]) ForEachSnapshot added in v0.2.0

func (s *Set[T]) ForEachSnapshot(fn func(key T) bool)

func (*Set[T]) Has

func (s *Set[T]) Has(key T) bool

Checks if a key exists in the set.

func (*Set[T]) Iterator added in v0.2.0

func (s *Set[T]) Iterator() iter.Seq[T]

func (*Set[T]) Keys

func (s *Set[T]) Keys() []T

Returns a slice of all keys in the set.

func (*Set[T]) Len

func (s *Set[T]) Len() int

Returns the number of keys in the set.

func (*Set[T]) Pop

func (s *Set[T]) Pop(key T) bool

Removes a key from the set and returns `true` if the key existed.

func (*Set[T]) PopIf added in v0.5.1

func (s *Set[T]) PopIf(key T, condition func(key T) bool) bool

PopIf removes a key from the set, but only if it exists and satisfies the condition. It returns true if the key was actually removed.

func (*Set[T]) SnapshotIterator added in v0.3.0

func (s *Set[T]) SnapshotIterator() iter.Seq[T]

type Tuple added in v0.2.0

type Tuple[K comparable, T any] struct {
	// contains filtered or unexported fields
}

Create a slice of key-value pairs

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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