MCPcopy Index your code
hub / github.com/enetx/g

github.com/enetx/g @v1.0.227

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.0.227 ↗ · + Follow
2,816 symbols 18,396 edges 241 files 891 documented · 32% 1 cross-repo links
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

g - Functional programming framework for Go.

Go Reference Go Report Card Coverage Status Go Mentioned in Awesome Go Ask DeepWiki

go get github.com/enetx/g

Requires Go 1.27+ (generic methods: Map, Then, Fold, Zip and friends change element types right in the chain — no more package-level Transform* workarounds)


Quick Start

package main

import (
    "fmt"
    "github.com/enetx/g"
)

func main() {
    // Slice with functional operations
    g.SliceOf(1, 2, 3, 4, 5).
        Iter().
        Filter(func(x int) bool { return x%2 == 0 }).
        Map(func(x int) int { return x * x }).
        Collect().
        Println() // Slice[4, 16]

    // Safe map access with Option
    m := g.NewMap[string, int]()
    m.Insert("key", 42)

    value := m.Get("key").UnwrapOr(0)
    fmt.Println(value) // 42

    // Result for error handling
    result := g.String("123").TryInt()
    if result.IsOk() {
        fmt.Println(result.Unwrap()) // 123
    }
}

Navigation

Core Collections Sync Types
Option Slice Mutex String
Result Map RwLock Int/Float
Iterators Set Pool Bytes
Heap File/Dir
Deque

Option

Safe nullable values: Some(value) or None.

opt := g.Some(42)           // Some(42)
none := g.None[int]()       // None

opt.IsSome()                // true
opt.Unwrap()                // 42 (panics if None)
opt.UnwrapOr(0)             // 42 (returns default if None)
opt.UnwrapOrDefault()       // 42 (returns zero value if None)

// From map lookup
v, ok := myMap[key]
opt := g.OptionOf(v, ok)

// Chaining
g.Some(5).Then(func(x int) g.Option[int] {
    return g.Some(x * 2)
}) // Some(10)

All Option Methods

Method Description
IsSome() / IsNone() Presence checks
IsSomeAnd(pred) / IsNoneOr(pred) Presence combined with a predicate
Some() Returns value (zero value if None — check first)
Unwrap() / Expect(msg) Returns value, panics if None
UnwrapOr(default) / UnwrapOrDefault() Returns value or fallback
Map(fn) Transforms the value, may change its type
MapOr(def, fn) / MapOrElse(defFn, fn) Map or fall back to a default
Then(fn) Chains a fallible transformation (and_then)
Filter(pred) Returns None if predicate fails
Or(other) / OrElse(fn) Fallback Option
Inspect(fn) Side effect on Some, returns self
OkOr(err) / OkOrElse(fn) Converts to Result
Take() / Replace(v) / Insert(v) In-place mutation
Option() Returns (value, bool)

JSON: Some(v) ⇄ value, Nonenull (encoding/json/v2 native, v1 compatible).


Result

Success (Ok) or failure (Err) with error.

ok := g.Ok(42)                              // Ok(42)
err := g.Err[int](errors.New("failed"))     // Err

ok.IsOk()                   // true
ok.Unwrap()                 // 42
err.UnwrapOr(0)             // 0

// From standard (value, error) pattern
result := g.ResultOf(strconv.Atoi("42"))    // Ok(42)
result := g.String("42").TryInt()           // Ok(42)

// Chaining
g.Ok(10).Then(func(x int) g.Result[int] {
    return g.Ok(x * 2)
}) // Ok(20)

// Convert to Option (discards error)
opt := result.Option()      // Some(42)

All Result Methods

Method Description
IsOk() / IsErr() State checks
IsOkAnd(pred) / IsErrAnd(pred) State combined with a predicate
Ok() / Err() Returns value / error (zero if the other state)
Unwrap() / Expect(msg) Returns value, panics if Err
UnwrapErr() Returns error, panics if Ok
UnwrapOr(default) / UnwrapOrDefault() Returns value or fallback
Map(fn) Transforms the value, may change its type
MapOr(def, fn) / MapOrElse(defFn, fn) Map or fall back
Then(fn) / ThenOf(fn) Chains Result / (T, error) functions
Or(other) / OrElse(fn) Fallback Result
MapErr(fn) / Wrap(err) Transforms / wraps the error
Inspect(fn) / InspectErr(fn) Side effects, return self
ErrIs(target) / ErrAs(target) errors.Is / errors.As integration
Option() / Result() Converts to Option / (value, error)

JSON: Ok(v){"ok": v}, Err(e){"err": "msg"} (externally tagged, like serde; duplicate keys rejected).


Slice

Extended slice with 90+ methods.

s := g.SliceOf(1, 2, 3, 4, 5)
s := g.NewSlice[int](0, 10)     // empty, with capacity 10 (one arg sets len AND cap)

s.Len()                         // Int(5)
s.Get(0)                        // Some(1)
s.Get(100)                      // None (safe!)
s.Last()                        // Some(5)
s.Contains(3)                   // true

s.Push(6, 7)                    // append in place
s.Pop()                         // Some(7)
s.Clone()                       // safe copy

// Sorting
s.SortBy(cmp.Cmp)               // ascending
s.Reverse()                     // in place
s.Shuffle()                     // random order

All Slice Methods

Category Methods
Access Get, Last, First, Random, RandomSample
Modify Set, Push, Pop, Insert, Remove, Clear
Search Contains, ContainsBy, Index, IndexBy
Transform Clone, Reverse, Shuffle, SortBy, SubSlice
Convert Iter, Heap, Std
Info Len, Cap, IsEmpty

Map

Extended map with Entry API.

m := g.NewMap[string, int]()
// or from pairs: g.MapOf(g.Pair[string, int]{"a", 1}, g.Pair[string, int]{"b", 2})

m.Insert("a", 1)                // insert value
m.Get("a")                      // Some(1)
m.Get("x")                      // None
m.Contains("a")                 // true
m.Remove("a")                   // remove

m.Keys()                        // Slice of keys
m.Values()                      // Slice of values

Entry API

Efficient update without multiple lookups:

// Insert if absent
m.Entry("counter").OrInsert(0)

// Update if present, insert if absent
m.Entry("counter").AndModify(func(v *int) { *v++ }).OrInsert(1)

// Lazy initialization
m.Entry("key").OrInsertWith(func() int {
    return expensiveComputation()
})

Word frequency example:

words := g.SliceOf("apple", "banana", "apple", "cherry", "banana", "apple")
freq := g.NewMap[string, int]()

for _, word := range words {
    freq.Entry(word).AndModify(func(v *int) { *v++ }).OrInsert(1)
}
// {"apple": 3, "banana": 2, "cherry": 1}

Entry Pattern Matching

switch e := m.Entry("key").(type) {
case g.OccupiedEntry[string, int]:
    fmt.Println("Exists:", e.Get())
    e.Insert(newValue)      // replace
    e.Remove()              // delete
case g.VacantEntry[string, int]:
    e.Insert(defaultValue)  // insert
}

Set

Collection of unique elements.

s := g.SetOf(1, 2, 3)
s.Insert(4)                     // add
s.Remove(1)                     // remove
s.Contains(2)                   // true

// Set algebra (lazy sequences)
s.Union(other)                  // A ∪ B
s.Intersection(other)           // A ∩ B
s.Difference(other)             // A \ B
s.SymmetricDifference(other)    // A △ B
s.Disjoint(other)               // no common elements?

Set Operations

a := g.SetOf(1, 2, 3, 4)
b := g.SetOf(3, 4, 5, 6)

a.Union(b).Collect()            // {1, 2, 3, 4, 5, 6}
a.Intersection(b).Collect()     // {3, 4}
a.Difference(b).Collect()       // {1, 2}
a.SymmetricDifference(b).Collect() // {1, 2, 5, 6}

a.Subset(b)                     // false
a.Superset(b)                   // false

Heap

Priority queue (binary heap).

import "github.com/enetx/g/cmp"

// Min-heap (smallest first)
h := g.NewHeap(cmp.Cmp[int])
h.Push(5, 3, 8, 1, 9)
// or in one go: g.HeapOf(cmp.Cmp[int], 5, 3, 8, 1, 9)

h.Peek()                        // Some(1)
h.Pop()                         // Some(1)
h.Pop()                         // Some(3)

// Max-heap (largest first)
maxH := g.NewHeap(func(a, b int) cmp.Ordering {
    return cmp.Cmp(b, a)
})

// From slice
heap := g.SliceOf(5, 3, 8, 1).Heap(cmp.Cmp)

Deque

Double-ended queue (ring buffer). O(1) at both ends.

dq := g.NewDeque[int]()
dq := g.DequeOf(1, 2, 3)

dq.PushFront(0)                 // add to front
dq.PushBack(4)                  // add to back

dq.Front()                      // Some(0)
dq.Back()                       // Some(4)

dq.PopFront()                   // Some(0)
dq.PopBack()                    // Some(4)

dq.Get(1)                       // element at index
dq.Len()                        // length
dq.IsEmpty()                    // true/false

Iterators

Functional operations on sequences.

g.SliceOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).
    Iter().
    Filter(func(x int) bool { return x%2 == 0 }).
    Map(func(x int) int { return x * x }).
    Take(3).
    Collect()
// [4, 16, 36]

Thanks to generic methods (Go 1.27+), transformations can change the element type right in the chain — just like Rust iterators:

g.SliceOf(1, 2, 3).
    Iter().
    Map(func(x int) g.String { return g.Int(x).String() }). // SeqSlice[int] -> SeqSlice[g.String]
    Collect().
    Join(", ").
    Println() // 1, 2, 3

// Fold into any accumulator type
words := g.SliceOf[g.String]("a", "bb", "ccc")
total := words.Iter().Fold(g.Int(0), func(acc g.Int, w g.String) g.Int { return acc + w.Len() })
// 6

// Typed Zip — pairs keep their real types
nums := g.SliceOf(1, 2, 3)
names := g.SliceOf("one", "two", "three")
nums.Iter().Zip(names.Iter()).ForEach(func(n int, s string) {
    fmt.Println(n, s)
})

Common Patterns

// Chain iterators
g.SliceOf(1, 2).Iter().Chain(g.SliceOf(3, 4).Iter()).Collect()
// [1, 2, 3, 4]

// Sum with Fold
g.SliceOf(1, 2, 3, 4, 5).Iter().Fold(0, func(acc, x int) int { return acc + x })
// 15

// Enumerate
g.SliceOf("a", "b", "c").Iter().Enumerate().ForEach(func(i g.Int, v string) {
    fmt.Printf("%d: %s\n", i, v)
})

// Using f package predicates
import "github.com/enetx/g/f"

g.SliceOf(1, 2, 3, 4, 5).Iter().Filter(f.Ne(3)).Collect()       // [1, 2, 4, 5]
g.SliceOf("", "a", "").Iter().Exclude(f.IsZero).Collect()       // ["a"]

All Iterator Methods

Transform Slice Combine Aggregate Search Other
Map Take Chain Collect Find ForEach
Filter Skip Zip Fold Any Inspect
Exclude StepBy Enumerate Reduce All Range
FilterMap First Intersperse Count MaxBy Scan
FlatMap Last Cycle CounterBy MinBy Combinations
Flatten Nth Partition Permutations
Dedup Chunks ChunkBy Context
Unique Windows Chan
SortBy TakeWhile
SkipWhile

Mutex

Typed mutex — data bound to lock.

counter := g.NewMutex(0)

// Lock and modify
guard := counter.Lock()
guard.Set(guard.Get() + 1)
guard.Unlock()

// With defer (recommended)
func increment(c *g.Mutex[int]) {
    guard := c.Lock()
    defer guard.Unlock()
    guard.Set(guard.Get() + 1)
}

// Direct pointer access
guard := counter.Lock()
defer guard.Unlock()
*guard.Deref() += 1

// Non-blocking
if opt := counter.TryLock(); opt.IsSome() {
    guard := opt.Unwrap()
    defer guard.Unlock()
    // got the lock
}

Why typed mutex?

// Traditional — easy to forget locking
type Old struct {
    mu   sync.Mutex
    data map[string]int  // what protects this?
}

// Typed — impossible to access without lock
type New struct {
    data *g.Mutex[g.Map[string, int]]
}

func (s *New) Get(key string) g.Option[int] {
    guard := s.data.Lock()
    defer guard.Unlock()
    return guard.Deref().Get(key)
}

RwLock

Multiple readers OR single writer.

config := g.NewRwLock(Config{Port: 8080})

// Read (concurrent)
func getPort(c *g.RwLock[Config]) int {
    guard := c.Read()
    defer guard.Unlock()
    return guard.Get().Port
}

// Write (exclusive)
func setPort(c *g.RwLock[Config], port int) {
    guard := c.Write()
    defer guard.Unlock()
    guard.Deref().Port = port
}

// Non-blocking
if opt := config.TryRead(); opt.IsSome() { ... }
if opt := config.TryWrite(); opt.IsSome() { ... }
Use Case Choose
Read-heavy (config, cache) RwLock
Write-heavy or balanced Mutex
Simple counters Mutex

Pool

Goroutine pool for parallel tasks.

```go import "github.com/enetx/g/pool"

p := pool.Newint.Limit(4)

for i := range 10 { p.Go(func() g.Result[int] { return g.Ok(i * 2) }) }

for result := range p.Wait() {

Extension points exported contracts — how you extend this code

OrdEntry (Interface)
OrdEntry is a sealed interface representing a view into a single MapOrd entry. OrdEntry provides an API for in-place ma
entry_ordered.go
Entry (Interface)
Entry is a sealed interface representing a view into a single Map entry. Entry provides an API for in-place manipulatio
entry.go
SafeEntry (Interface)
SafeEntry is a sealed interface representing a view into a single MapSafe entry. SafeEntry provides an API for in-place
entry_safe.go
Signed (Interface)
Signed is a constraint that permits any signed integer type. If future releases of Go add new predeclared signed integer
constraints/constraints.go
File (Interface)
A File provides the minimal set of methods required to lock an open file. File implementations must be usable as map key
internal/filelock/filelock.go
Unsigned (Interface)
Unsigned is a constraint that permits any unsigned integer type. If future releases of Go add new predeclared unsigned i
constraints/constraints.go
Integer (Interface)
Integer is a constraint that permits any integer type. If future releases of Go add new predeclared integer types, this
constraints/constraints.go
Float (Interface)
Float is a constraint that permits any floating-point type. If future releases of Go add new predeclared floating-point
constraints/constraints.go

Core symbols most depended-on inside this repo

Iter
called by 830
map.go
Insert
called by 782
map.go
Println
called by 676
map.go
Collect
called by 649
map_iter.go
Some
called by 578
option.go
Len
called by 577
map.go
Ok
called by 557
result.go
Get
called by 349
map.go

Shape

Function 2,047
Method 604
Struct 123
TypeAlias 31
Interface 11

Languages

Go100%

Modules by API surface

tests/bytes_test.go87 symbols
tests/file_test.go83 symbols
tests/slice_test.go79 symbols
tests/string_test.go76 symbols
tests/slice_iter_test.go65 symbols
tests/dir_test.go61 symbols
tests/map_ordered_test.go54 symbols
tests/deque_test.go52 symbols
tests/pool/pool_test.go49 symbols
tests/deque_iter_test.go47 symbols
tests/result_json_test.go45 symbols
tests/heap_iter_test.go45 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

Datastores touched

dbDatabase · 1 repos

For agents

$ claude mcp add g \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact