English | 简体中文
op is a carefully crafted Go utility toolkit providing reusable, generic-first packages for common programming tasks. Each package is designed for performance and usability, with clean APIs that integrate naturally into Go projects. Import the top-level package to access all functionality without managing individual sub-package dependencies.
- High Performance: Optimized implementations — O(1) deque operations, ring-buffer backing, zero-allocation paths where possible.
- Generic Support: Full support for Go generics with type-safe APIs across all collection and utility packages.
- Modular Design: Each sub-package is self-contained and can be used independently or through the unified entry point.
- Clean API: Consistent patterns — method chaining, safe variants (
Try*/Peek*), and idiomatic error handling. - Well Tested: Comprehensive unit test coverage across all packages.
A high-performance generic deque backed by a ring buffer. All head and tail operations are O(1). The buffer auto-expands on push and shrinks when sparsely populated. Supports random access, rotation, insertion, and predicate-based search.
d:= op.NewDeque[int](64) // pre-allocate ring buffer capacityd.PushBack(1) // [1]d.PushBack(2) // [1, 2]d.PushFront(0) // [0, 1, 2]d.PushBack(3) // [0, 1, 2, 3]d.PopFront() // returns 0, panics if emptyd.Rotate(1) // rotate forward: [3, 1, 2]d.Insert(1, 99) // [3, 99, 1, 2]// Safe access without panicsifv, ok:=d.PeekFront(); ok {
// use v
}
// Search for matching elementidx:=d.Index(func(xint) bool { returnx>50 }) // idx=1 → 99Docs: deque/README.md | 中文文档
A generic publish-subscribe system with typed events and payloads. Supports asynchronous fire-and-forget, concurrent emit-with-wait, and fully synchronous dispatch. Provides listener lifecycle management via subscriptions, one-time listeners, panic recovery, and configurable concurrency limits.
// E = event type (comparable), T = payload typeem:=op.NewEmitter[string, int]()
// Subscribe with lifecycle managementsub:=em.On("order.created", func(amountint) {
fmt.Printf("New order: $%d\n", amount)
})
defersub.Unsubscribe()
// One-shot listenerem.Once("startup", func(vint) { fmt.Println("Init complete") })
// Fire and forget (async)em.Emit("order.created", 150)
// Fire concurrently and wait for all listenersem.EmitWait("order.created", 200)
// Fire synchronously, in registration orderem.EmitSync("order.created", 300)
// Recover from listener panicsem.RecoverWith(func(eventstring, listenerany, panicValany) {
log.Printf("Panic in listener for %s: %v", event, panicVal)
})
// Limit concurrent listener goroutinesem.SetConcurrency(4)Docs: emission/README.md
A chainable query API for Go slices inspired by .NET LINQ. Provides filtering, projection, sorting, grouping, aggregation, set operations, and joins — all with lazy evaluation where applicable. Over 40 operations spanning element access, partitioning, and conversion. Linq is a value type; most chain methods return copies.
import (
"github.com/wsshow/op""github.com/wsshow/op/linq"
)
// --- Filtering and projection ---results:=op.LinqFrom([]int{1, 2, 3, 4, 5, 6}).
Where(func(xint) bool { returnx%2==0 }).
Select(func(xint) int { returnx*10 }).
Results()
// results = [20, 40, 60]// --- Sorting with multi-level keys ---users:= []struct{ Namestring; Ageint }{{"Alice", 30}, {"Bob", 25}, {"Carol", 35}}
ordered:=linq.OrderBy(op.LinqFrom(users),
func(ustruct{ Namestring; Ageint }) int { returnu.Age },
).ThenByDescending(func(a, bstruct{ Namestring; Ageint }) int {
returnstrings.Compare(a.Name, b.Name)
})
for_, u:=rangeordered.Results() {
fmt.Println(u.Name, u.Age)
}
// --- Aggregation ---nums:=op.LinqFrom([]int{10, 20, 30, 40})
sum:=linq.Sum(nums) // 100avg:=linq.Average(nums) // 25.0min, _:=linq.MinVal(nums) // 10cnt:=nums.CountBy(func(xint) bool { returnx>20 }) // 2// --- Set operations (comparable types) ---a:=op.LinqFrom([]int{1, 2, 3, 4})
b:=op.LinqFrom([]int{3, 4, 5, 6})
union:=linq.Union(a, b) // [1, 2, 3, 4, 5, 6]inter:=linq.Intersect(a, b) // [3, 4]diff:=linq.Except(a, b) // [1, 2]// --- Grouping ---words:=op.LinqFrom([]string{"apple", "banana", "apricot", "blueberry", "avocado"})
groups:=linq.GroupBy(words, func(wstring) string { returnstring(w[0]) })
for_, g:=rangegroups {
fmt.Printf("Key %s: %v\n", g.Key, g.Items)
}
// --- Joins ---orders:=op.LinqFrom([]struct{ ID, UserIDint }{{1, 100}, {2, 200}})
customers:=op.LinqFrom([]struct{ IDint; Namestring }{{100, "Alice"}, {200, "Bob"}})
joined:=linq.Join(
orders, customers,
func(ostruct{ ID, UserIDint }) int { returno.UserID },
func(cstruct{ IDint; Namestring }) int { returnc.ID },
func(ostruct{ ID, UserIDint }, cstruct{ IDint; Namestring }) string {
returnfmt.Sprintf("Order #%d by %s", o.ID, c.Name)
},
)Docs: linq/README.md
Tools for spawning, monitoring, and managing external processes with full lifecycle control. Supports stdout/stderr line callbacks, automatic restart with interval gating, graceful shutdown with configurable timeouts, and multi-process orchestration via Manager.
// --- Single process ---proc:=op.NewProcess(op.Options{
ExecPath: "my-server",
Args: []string{"--port", "8080", "--verbose"},
Env: []string{"LOG_LEVEL=debug"},
OnStdout: func(linestring) { log.Println("OUT:", line) },
OnStderr: func(linestring) { log.Println("ERR:", line) },
OnBefore: func(p*op.Process) { log.Println("Starting...") },
OnAfter: func(p*op.Process) { log.Printf("Exited with code %d", p.ExitCode()) },
})
iferr:=proc.Start(); err!=nil {
log.Fatal(err)
}
// Wait for completion<-proc.Done()
log.Printf("Exit code: %d", proc.ExitCode())
// Graceful restart with backpressureproc.Restart()
// Signal handlingproc.Signal(os.Interrupt)
// Custom stop timeoutproc.StopWithTimeout(10*time.Second)
// --- Multi-process manager ---mgr:=op.NewProcessManager()
mgr.Add("api", op.Options{
ExecPath: "./api-server",
Args: []string{"--port", "8080"},
})
mgr.Add("worker", op.Options{
ExecPath: "./worker",
Args: []string{"--queue", "default"},
})
// Query and controlifp, ok:=mgr.Get("api"); ok {
log.Printf("API PID: %d", p.Pid())
}
// Iterate all processesmgr.Range(func(namestring, p*op.Process) bool {
log.Printf("%s: running=%v", name, p.IsRunning())
returntrue
})
// Bulk operationsmgr.RestartAll()
defermgr.StopAllWithTimeout(15*time.Second)Docs: process/README.md | 中文文档
A generic slice wrapper with functional operations inspired by JavaScript's array methods. Supports map, filter, reduce, element insertion/removal at arbitrary positions, sorting, reversal, concatenation, and safe access. Most mutation methods return *Slice for chaining.
import (
"github.com/wsshow/op""github.com/wsshow/op/slice"
)
s:=op.NewSlice(1, 2, 3)
// --- Mutation (in-place, chainable) ---s.Push(4, 5).Unshift(0)
// s = [0, 1, 2, 3, 4, 5]val, ok:=s.Pop() // val=5, ok=trueval, ok=s.Shift() // val=0, ok=trues.Insert(2, 99) // [1, 2, 99, 3, 4]// --- Functional operations (return new Slice) ---doubled:=s.Map(func(xint) int { returnx*2 })
evens:=s.Filter(func(xint) bool { returnx%2==0 })
// --- Type conversion ---strs:=slice.MapTo(s, func(xint) string { returnstrconv.Itoa(x) })
// strs is *Slice[string]// --- Reduction ---sum:=s.Reduce(func(acc, curint) int { returnacc+cur }, 0)
// --- Sorting ---s.Sort(func(a, bint) bool { returna<b })
s.Reverse()
// --- Safe access ---ifv, ok:=s.Find(func(xint) bool { returnx>50 }); ok {
// use v
}
found:=s.Some(func(xint) bool { returnx>3 }) // true if any matchallPos:=s.Every(func(xint) bool { returnx>0 }) // true if all match// --- Combine slices ---other:=op.NewSlice(10, 20, 30)
merged:=s.Concat(other) // new Slice, originals unchangedDocs: slice/README.md | 中文文档
A string wrapper with common text operations. Most methods mutate in-place and return *String for chaining. Includes parsing helpers, Unicode-aware reversal, formatting, and substring extraction with Python-style negative indexing.
s:=op.NewString(" Hello, World! ")
// --- Transformation (in-place, chainable) ---s.TrimSpace().ToLower().ReplaceAll("world", "Gopher")
// s.String() = "hello, Gopher!"// --- Inspection ---s.Contains("Gopher") // trues.StartsWith("hello") // trues.Count("o") // 2s.Length() // 15s.RuneLength() // 15 (Unicode-aware)// --- Parsing ---numStr:=op.NewString(" 42 ")
val, err:=numStr.TrimSpace().ToInt() // val=42// --- Non-mutating (return new *String) ---cloned:=s.Clone()
formatted:=op.NewString("Hello, %s!").Format("World") // "Hello, World!"sub:=s.Substring(7, 12) // "Gopher"joined:=op.JoinStrings([]string{"a", "b", "c"}, ",") // "a,b,c"// --- Unicode-aware operations ---op.NewString("こんにちは").Reverse() // "はちにんこ"Docs: str/README.md
A high-performance goroutine pool that limits concurrency and queues overflow tasks. Workers are dynamically created on demand and reclaimed after an idle timeout. Supports pause/resume with context-based timeouts, graceful shutdown modes, and panic recovery.
wp:=op.NewWorkerPool(4, // max concurrent workersop.WithPanicHandler(func(vany) {
log.Printf("Task panicked: %v", v)
}),
)
// Submit fire-and-forget tasksfori:=0; i<100; i++ {
i:=iwp.Submit(func() {
// process item itime.Sleep(50*time.Millisecond)
})
}
// Submit and wait for a specific task to completewp.SubmitWait(func() {
// critical pre-flight checklog.Println("Pre-flight complete")
})
// Inspect queue pressurequeued:=wp.WaitingQueueSize()
log.Printf("Tasks waiting: %d", queued)
// Pause all workers temporarilyctx, cancel:=context.WithTimeout(context.Background(), 5*time.Second)
defercancel()
wp.Pause(ctx) // blocks until workers pause or context expires// Graceful shutdown — complete queued tasks, then stopwp.StopWait()
// Immediate shutdown — finish running tasks, discard queued// wp.Stop()Docs: workerpool/README.md | 中文文档
A lightweight coroutine-style generator using goroutines and channels. The generator function yields values via Yield.Send(). The consumer retrieves them with Next() and can optionally send results back at each step, enabling bidirectional communication between producer and consumer.
// --- Basic value generation ---g:=op.NewGenerator(func(yield op.Yield[int]) {
fori:=0; i<5; i++ {
ifyield.Stopped() {
return// consumer requested stop
}
// yield.Send blocks until consumer calls Nextresult:=yield.Send(i)
fmt.Printf("Generator received: %v\n", result)
}
})
// Consume all valuesfor {
val, done:=g.Next("ack") // "ack" sent back to generatorifdone {
break
}
fmt.Printf("Consumer got: %d\n", val)
}
// --- Infinite sequence with early stop ---fibGen:=op.NewGenerator(func(yield op.Yield[int]) {
a, b:=0, 1for {
ifyield.Stopped() {
return
}
yield.Send(a)
a, b=b, a+b
}
})
// Take first 10 Fibonacci numbersfori:=0; i<10; i++ {
v, done:=fibGen.Next()
ifdone {
break
}
fmt.Println(v) // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
}
fibGen.Stop()Docs: generator/README.md | 中文文档
go get github.com/wsshow/op
Import the top-level package to access all types and constructors:
import"github.com/wsshow/op"Alternatively, import individual sub-packages for a lighter dependency footprint:
import (
"github.com/wsshow/op/deque""github.com/wsshow/op/linq"
)package main
import (
"context""fmt""log""time""github.com/wsshow/op"
)
funcmain() {
// String manipulation with chainings:=op.NewString(" Hello, World! ")
s.TrimSpace().ToUpper().ReplaceAll("WORLD", "GOPHER")
fmt.Println(s) // "HELLO, GOPHER!"// Slice with functional operationssl:=op.NewSlice(1, 2, 3, 4, 5).
Filter(func(xint) bool { returnx%2!=0 }).
Map(func(xint) int { returnx*x })
fmt.Println(sl.Data()) // [1, 9, 25]// Type-safe event emitterem:=op.NewEmitter[string, string]()
em.On("message", func(payloadstring) {
fmt.Println("Received:", payload)
})
em.Emit("message", "Hello from emitter")
// LINQ filtering and chainingscores:=op.LinqFrom([]int{85, 92, 78, 95, 88})
passed:=scores.
Where(func(xint) bool { returnx>=80 }).
Sort(func(a, bint) bool { returna<b })
fmt.Println(passed.Results()) // [85, 88, 92, 95]fmt.Println("Passed:", passed.Count(), "out of", scores.Count()) // 4 out of 5// High-performance dequed:= op.NewDeque[string](8)
d.PushBack("alpha")
d.PushBack("beta")
d.PushFront("omega")
ford.Size() >0 {
fmt.Println(d.PopFront())
}
// Coroutine-style generatorg:=op.NewGenerator(func(yield op.Yield[int]) {
fori:=1; i<=3; i++ {
yield.Send(i*10)
}
})
for {
v, done:=g.Next()
ifdone {
break
}
fmt.Println(v) // 10, 20, 30
}
// Worker pool with panic recoverywp:=op.NewWorkerPool(4, op.WithPanicHandler(func(vany) {
log.Printf("Recovered from panic: %v", v)
}))
fori:=0; i<20; i++ {
i:=iwp.Submit(func() {
fmt.Printf("Task %d running\n", i)
})
}
wp.StopWait()
// Process managementproc:=op.NewProcess(op.Options{
ExecPath: "echo",
Args: []string{"hello"},
OnStdout: func(linestring) { fmt.Println("OUT:", line) },
})
iferr:=proc.Run(); err!=nil {
log.Fatal(err)
}
// Multi-process managermgr:=op.NewProcessManager()
mgr.Add("healthcheck", op.Options{
ExecPath: "curl",
Args: []string{"-s", "http://localhost:8080/health"},
})
defermgr.StopAll()
}op/
├── deque/ # Generic ring-buffer deque
├── emission/ # Typed event emitter for pub/sub
├── linq/ # LINQ-style chainable query library
├── process/ # External process lifecycle management
├── slice/ # Generic slice wrapper with functional ops
├── str/ # String wrapper with chaining
├── workerpool/ # Bounded goroutine pool
├── generator/ # Coroutine-style generator
└── op.go # Unified entry point with type aliases
Contributions are welcome. Please ensure existing tests pass and new functionality includes test coverage. Open an issue to discuss significant changes before submitting a PR.
MIT - see LICENSE for details.
- deque - Inspiration for the ring-buffer deque
- workerpool - Inspiration for the worker pool
- emission - Inspiration for the event emitter