Write Go code that's as safe as Rust, as expressive as functional programming, and as fast as native Go.
A zero-dependency library that brings Rust's most powerful patterns to Go, eliminating error boilerplate, nil panics, and imperative loops.
gust is a production-ready Go library that brings Rust's most powerful patterns to Go. It transforms how you write Go code by providing:
- Type-safe error handling with
Result[T]- eliminateif err != nilboilerplate - Safe optional values with
Option[T]- no more nil pointer panics - Declarative iteration with 60+ iterator methods - write data pipelines like Rust
With zero dependencies and full type safety, gust lets you write Go code that's safer, cleaner, and more expressiveβwithout sacrificing performance.
gust introduces the result.Ret + Unwrap + Catch patternβa revolutionary way to handle errors in Go:
func fetchUserData(userID int) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
user := result.Ret(db.GetUser(userID)).Unwrap()
profile := result.Ret(api.GetProfile(user.Email)).Unwrap()
return result.Ok(fmt.Sprintf("%s: %s", user.Name, profile.Bio))
}One line (defer r.Catch()) eliminates all if err != nil checks. Errors automatically propagate via panic and are caught, converted to Result, and returned.
| Traditional Go | With gust |
|---|---|
| β 15+ lines of error checks | β 3 lines with Catch pattern |
β if err != nil everywhere |
β
defer r.Catch() once |
| β Nil pointer panics | β Compile-time safety |
| β Imperative loops | β Declarative pipelines |
| β Hard to compose | β Elegant method chaining |
go get github.com/andeya/gustpackage main
import (
"fmt"
"github.com/andeya/gust/result"
)
func main() {
// Using Catch pattern - errors flow automatically!
processValue := func(value int) (r result.Result[int]) {
defer r.Catch()
doubled := value * 2
if doubled > 20 {
return result.TryErr[int]("too large")
}
return result.Ok(doubled + 5)
}
res := processValue(10)
if res.IsOk() {
fmt.Println("Success:", res.Unwrap())
} else {
fmt.Println("Error:", res.UnwrapErr())
}
}Output: Success: 25
func fetchUserData(userID int) (string, error) {
user, err := db.GetUser(userID)
if err != nil {
return "", fmt.Errorf("db error: %w", err)
}
if user == nil {
return "", fmt.Errorf("user not found")
}
if user.Email == "" {
return "", fmt.Errorf("invalid user: no email")
}
profile, err := api.GetProfile(user.Email)
if err != nil {
return "", fmt.Errorf("api error: %w", err)
}
if profile == nil {
return "", fmt.Errorf("profile not found")
}
return fmt.Sprintf("%s: %s", user.Name, profile.Bio), nil
}Problems:
- β 4 repetitive
if err != nilchecks - β 3 nested conditionals
- β Hard to test individual steps
- β Easy to forget error handling
- β 15+ lines of boilerplate
import "github.com/andeya/gust/result"
func fetchUserData(userID int) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
user := result.Ret(db.GetUser(userID)).Unwrap()
if user == nil || user.Email == "" {
return result.TryErr[string]("invalid user")
}
profile := result.Ret(api.GetProfile(user.Email)).Unwrap()
if profile == nil {
return result.TryErr[string]("profile not found")
}
return result.Ok(fmt.Sprintf("%s: %s", user.Name, profile.Bio))
}Benefits:
- β
One line error handling -
defer r.Catch()handles everything - β Linear flow - Easy to read top-to-bottom
- β Automatic propagation - Errors stop execution automatically
- β Composable - Each step is independent and testable
- β Type-safe - Compiler enforces correct error handling
- β 70% less code - From 15+ lines to 8 lines
The Catch pattern (result.Ret + Unwrap + Catch) is gust's most powerful feature:
import "github.com/andeya/gust/result"
// Before: Traditional Go (multiple error checks)
// func readConfig(filename string) (string, error) {
// f, err := os.Open(filename)
// if err != nil {
// return "", err
// }
// defer f.Close()
// data, err := io.ReadAll(f)
// if err != nil {
// return "", err
// }
// return string(data), nil
// }
// After: gust Catch pattern (linear flow, no error checks)
func readConfig(filename string) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
data := result.Ret(os.ReadFile(filename)).Unwrap()
return result.Ok(string(data))
}Key Methods:
result.Ret(T, error)- Convert(T, error)toResult[T]Unwrap()- Extract value (panics if error, caught byCatch)defer r.Catch()- Catch all panics and convert toResulterrorsMap- Transform value if OkAndThen- Chain operations returning ResultUnwrapOr- Extract safely with default (never panics)
Real-World Use Cases:
- API call chains
- Database operations
- File I/O operations
- Data validation pipelines
Replace *T and (T, bool) with safe Option[T] that prevents nil pointer panics:
import "github.com/andeya/gust/option"
// Before: Traditional Go (nil checks everywhere)
// func divide(a, b float64) *float64 {
// if b == 0 {
// return nil
// }
// result := a / b
// return &result
// }
// result := divide(10, 2)
// if result != nil {
// fmt.Println(*result * 2) // Risk of nil pointer panic
// }
// After: gust Option (type-safe, no nil panics)
divide := func(a, b float64) option.Option[float64] {
if b == 0 {
return option.None[float64]()
}
return option.Some(a / b)
}
quotient := divide(10, 2).
Map(func(x float64) float64 { return x * 2 }).
UnwrapOr(0) // Safe: never panics
fmt.Println(quotient) // 10Key Methods:
Map- Transform value if SomeAndThen- Chain operations returning OptionFilter- Conditionally filter valuesUnwrapOr- Extract safely with default (never panics)
Real-World Use Cases:
- Configuration reading
- Optional function parameters
- Map lookups
- JSON unmarshaling
Full Rust Iterator trait implementation with 60+ methods for declarative data processing:
import "github.com/andeya/gust/iterator"
// Before: Traditional Go (nested loops, manual error handling)
// func processNumbers(input []string) ([]int, error) {
// var results []int
// for _, s := range input {
// n, err := strconv.Atoi(s)
// if err != nil {
// continue
// }
// if n > 0 {
// results = append(results, n*2)
// }
// }
// return results, nil
// }
// After: gust Iterator (declarative, type-safe, 70% less code)
input := []string{"10", "20", "invalid", "30", "0", "40"}
results := iterator.FilterMap(
iterator.RetMap(iterator.FromSlice(input), strconv.Atoi),
result.Result[int].Ok,
).
Filter(func(x int) bool { return x > 0 }).
Map(func(x int) int { return x * 2 }).
Take(3).
Collect()
fmt.Println(results) // [20 40 60]Highlights:
- π 60+ methods from Rust's Iterator trait
- π Lazy evaluation - Computations happen on-demand
- π Method chaining - Compose complex operations elegantly
- π Go 1.24+ integration - Works with standard
iter.Seq[T] - π― Type-safe - Compile-time guarantees
- β‘ Zero-cost abstractions - No performance overhead
Method Categories:
- Constructors:
FromSlice,FromRange,FromFunc,Empty,Once,Repeat - BitSet Iterators:
FromBitSet,FromBitSetOnes,FromBitSetZeros - Go Integration:
FromSeq,Seq,Pull(Go 1.24+ standard iterators) - Basic Adapters:
Map,Filter,Chain,Zip,Enumerate - Filtering:
Skip,Take,StepBy,SkipWhile,TakeWhile - Transforming:
MapWhile,Scan,FlatMap,Flatten - Chunking:
MapWindows,ArrayChunks,ChunkBy - Consumers:
Collect,Fold,Reduce,Count,Sum,Product,Partition - Search:
Find,FindMap,Position,All,Any - Min/Max:
Max,Min,MaxBy,MinBy,MaxByKey,MinByKey - Double-Ended:
NextBack,Rfold,Rfind,NthBack
Before: Traditional Go (nested loops + error handling, 15+ lines)
func processUserInput(input []string) ([]int, error) {
var results []int
for _, s := range input {
n, err := strconv.Atoi(s)
if err != nil {
continue
}
if n > 0 {
results = append(results, n*2)
}
}
if len(results) == 0 {
return nil, fmt.Errorf("no valid numbers")
}
return results, nil
}After: gust Iterator + Result (declarative, type-safe, 8 lines)
import (
"github.com/andeya/gust/iterator"
"github.com/andeya/gust/result"
"strconv"
)
input := []string{"10", "20", "invalid", "30", "0", "40"}
results := iterator.FilterMap(
iterator.RetMap(iterator.FromSlice(input), strconv.Atoi),
result.Result[int].Ok,
).
Filter(func(x int) bool { return x > 0 }).
Map(func(x int) int { return x * 2 }).
Take(3).
Collect()
fmt.Println(results) // [20 40 60]Result: 70% less code, type-safe, declarative
Before: Traditional Go (15+ lines, 4 error checks)
func fetchUserProfile(userID int) (string, error) {
user, err := db.GetUser(userID)
if err != nil {
return "", fmt.Errorf("db error: %w", err)
}
if user == nil || user.Email == "" {
return "", fmt.Errorf("invalid user")
}
profile, err := api.GetProfile(user.Email)
if err != nil {
return "", fmt.Errorf("api error: %w", err)
}
if profile == nil {
return "", fmt.Errorf("profile not found")
}
return fmt.Sprintf("%s: %s", user.Name, profile.Bio), nil
}After: gust Catch Pattern (8 lines, 0 error checks)
import "github.com/andeya/gust/result"
func fetchUserProfile(userID int) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
user := result.Ret(db.GetUser(userID)).Unwrap()
if user == nil || user.Email == "" {
return result.TryErr[string]("invalid user")
}
profile := result.Ret(api.GetProfile(user.Email)).Unwrap()
if profile == nil {
return result.TryErr[string]("profile not found")
}
return result.Ok(fmt.Sprintf("%s: %s", user.Name, profile.Bio))
}
// Usage
profileRes := fetchUserProfile(123)
if profileRes.IsOk() {
fmt.Println(profileRes.Unwrap())
} else {
fmt.Println("Error:", profileRes.UnwrapErr())
}Result: 70% less code, linear flow, automatic error propagation
Before: Traditional Go (multiple error checks, nested conditions)
func copyDirectory(src, dst string) error {
info, err := os.Stat(src)
if err != nil {
return err
}
if err = os.MkdirAll(dst, info.Mode()); err != nil {
return err
}
entries, err := os.ReadDir(src)
if err != nil {
return err
}
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
if entry.IsDir() {
if err = copyDirectory(srcPath, dstPath); err != nil {
return err
}
} else {
if err = copyFile(srcPath, dstPath); err != nil {
return err
}
}
}
return nil
}After: gust Catch Pattern (linear flow, single error handler)
import (
"github.com/andeya/gust/fileutil"
"github.com/andeya/gust/result"
"os"
"path/filepath"
)
func copyDirectory(src, dst string) (r result.VoidResult) {
defer r.Catch() // One line handles ALL errors!
info := result.Ret(os.Stat(src)).Unwrap()
result.RetVoid(os.MkdirAll(dst, info.Mode())).Unwrap()
entries := result.Ret(os.ReadDir(src)).Unwrap()
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
if entry.IsDir() {
copyDirectory(srcPath, dstPath).Unwrap()
} else {
fileutil.CopyFile(srcPath, dstPath).Unwrap()
}
}
return result.OkVoid()
}Result: Linear code flow, automatic error propagation, 70% less code
Before: Traditional Go (nil checks, error handling)
type Config struct {
APIKey *string
Port int
}
func loadConfig() (Config, error) {
apiKeyEnv := os.Getenv("API_KEY")
var apiKey *string
if apiKeyEnv != "" {
apiKey = &apiKeyEnv
}
portStr := os.Getenv("PORT")
port := 8080
if portStr != "" {
p, err := strconv.Atoi(portStr)
if err != nil {
return Config{}, err
}
port = p
}
return Config{APIKey: apiKey, Port: port}, nil
}After: gust Option (type-safe, no nil checks)
import (
"github.com/andeya/gust/option"
"os"
"strconv"
)
type Config struct {
APIKey option.Option[string]
Port option.Option[int]
}
func loadConfig() Config {
apiKeyEnv := os.Getenv("API_KEY")
var apiKeyPtr *string
if apiKeyEnv != "" {
apiKeyPtr = &apiKeyEnv
}
return Config{
APIKey: option.ElemOpt(apiKeyPtr),
Port: option.RetOpt(strconv.Atoi(os.Getenv("PORT"))),
}
}
config := loadConfig()
port := config.Port.UnwrapOr(8080) // Default to 8080 if not set
apiKey := config.APIKey.UnwrapOr("") // Default to empty stringResult: Type-safe, no nil checks, elegant defaults
gust provides a comprehensive set of utility packages organized into three categories:
The foundation of gust's type-safe programming model:
Eliminate if err != nil boilerplate with the revolutionary Catch pattern:
import "github.com/andeya/gust/result"
func readFile(filename string) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
data := result.Ret(os.ReadFile(filename)).Unwrap()
return result.Ok(string(data))
}Key Features: Result[T], Catch pattern, Map, AndThen, UnwrapOr
Replace *T and (T, bool) with type-safe Option[T]:
import "github.com/andeya/gust/option"
divide := func(a, b float64) option.Option[float64] {
if b == 0 {
return option.None[float64]()
}
return option.Some(a / b)
}
quotient := divide(10, 2).UnwrapOr(0) // Safe: never panicsKey Features: Option[T], Map, Filter, AndThen, UnwrapOr
60+ methods for declarative data processing:
import "github.com/andeya/gust/iterator"
sum := iterator.FromSlice([]int{1, 2, 3, 4, 5}).
Filter(func(x int) bool { return x%2 == 0 }).
Map(func(x int) int { return x * x }).
Fold(0, func(acc, x int) int { return acc + x })Key Features: 60+ methods, lazy evaluation, method chaining, Go 1.24+ integration
Generic utilities for common data structures:
Type-safe map operations with Option return types:
import "github.com/andeya/gust/dict"
m := map[string]int{"a": 1, "b": 2}
value := dict.Get(m, "b") // Returns Option[int]
if value.IsSome() {
fmt.Println(value.Unwrap()) // 2
}Key Features: Filter, Map, Keys, Values, Get
Type-safe slice operations:
import "github.com/andeya/gust/vec"
numbers := []int{1, 2, 3}
doubled := vec.MapAlone(numbers, func(x int) int { return x * 2 })Key Features: MapAlone, Get, Copy, Dict
Efficient bit manipulation with iterator integration:
import "github.com/andeya/gust/bitset"
bs := bitset.New(64)
bs.Set(0).Set(2).Set(5)
ones := iterator.FromBitSetOnes(bs).Collect() // [0, 2, 5]Key Features: Bitwise operations, iterator integration, multiple encodings
Production-ready tools for common tasks:
Zero-copy conversions and string manipulation:
import "github.com/andeya/gust/conv"
// Zero-copy byte/string conversion
bytes := []byte{'h', 'e', 'l', 'l', 'o'}
str := conv.BytesToString[string](bytes)
// Case conversion
snake := conv.ToSnakeCase("UserID") // "user_id"
camel := conv.ToCamelCase("user_id") // "UserId"Key Features: BytesToString, StringToReadonlyBytes, case conversion, JSON quoting
Base 2-62 conversion with overflow protection:
import "github.com/andeya/gust/digit"
// Format in different bases
fmt.Println(digit.FormatUint(255, 16)) // "ff"
fmt.Println(digit.FormatUint(255, 62)) // "47"
// Parse with error handling
parsed := digit.ParseInt("ff", 16, 64) // Result[int64]Key Features: Base 2-62 conversion, FormatInt, ParseInt, checked operations
Cryptographically secure random generation with timestamp embedding:
import "github.com/andeya/gust/random"
gen := random.NewGenerator(false) // base62 encoding
str := gen.RandomString(16).Unwrap()
timestamped := gen.StringWithNow(20).Unwrap() // Includes timestampKey Features: Base36/Base62 encoding, timestamp embedding, secure generation
Complete hash suite and AES encryption:
import "github.com/andeya/gust/encrypt"
// Hash functions
hash := encrypt.SHA256([]byte("hello"), encrypt.EncodingHex)
// AES encryption
key := []byte("1234567890123456")
encrypted := encrypt.EncryptAES(key, []byte("secret"),
encrypt.ModeCBC, encrypt.EncodingHex)Key Features: MD5, SHA series, FNV, CRC, Adler-32, AES encryption
Enhanced error handling with stack traces:
import "github.com/andeya/gust/errutil"
// Error boxing
errBox := errutil.BoxErr(errors.New("error"))
err := errBox.ToError()
// Stack traces
stack := errutil.GetStackTrace(0)Key Features: Stack traces, panic recovery, ErrBox
Type-safe file operations with Result types:
import "github.com/andeya/gust/fileutil"
// Copy file
res := fileutil.CopyFile("src.txt", "dst.txt")
// Archive directory
fileutil.TarGz("src/", "archive.tar.gz", false, nil, ".git")Key Features: Path manipulation, file I/O, directory operations, tar.gz archiving
30x faster than time.Now() for high-frequency operations:
import "github.com/andeya/gust/coarsetime"
// Use default instance (100ms precision)
now := coarsetime.Now()
elapsed := coarsetime.Since(start) // Monotonic time
// Create instance with default precision (100ms)
ct := coarsetime.New() // Uses default 100ms precision
defer ct.Stop()
now := ct.Now()
// Create custom precision instance
ct2 := coarsetime.New(10 * time.Millisecond) // 10ms precision
defer ct2.Stop()
now2 := ct2.Now()Key Features: Wall clock & monotonic time, configurable precision, 30x faster
Signal handling and cleanup hooks:
import "github.com/andeya/gust/shutdown"
s := shutdown.New()
s.SetHooks(
func() result.VoidResult { /* first sweep */ },
func() result.VoidResult { /* final cleanup */ },
)
go s.Listen() // Blocks until signalKey Features: Signal handling, cleanup hooks, graceful process restart (Unix)
Thread-safe data structures:
import "github.com/andeya/gust/syncutil"
// Thread-safe map
var m syncutil.SyncMap[string, int]
m.Store("key", 42)
value := m.Load("key") // Returns Option[int]
// Lazy initialization
lazy := syncutil.NewLazyValueWithFunc(func() result.Result[int] {
return result.Ok(expensiveComputation())
})Key Features: SyncMap, Lazy, mutex wrappers
Generic type constraints for compile-time safety:
import "github.com/andeya/gust/constraints"
func max[T constraints.Ord](a, b T) T {
if constraints.Compare(a, b).IsGreater() {
return a
}
return b
}Key Features: Ordering, Numeric, Digit
gust has zero external dependencies. It only uses Go's standard library, keeping your project lean and secure.
- β Comprehensive test coverage
- β Full documentation with examples
- β Battle-tested in production
- β Active maintenance and support
All operations are type-safe with compile-time guarantees. The Go compiler enforces correct usage.
gust uses zero-cost abstractions. There's no runtime overhead compared to traditional Go code.
Seamlessly works with Go 1.24+'s standard iter.Seq[T] iterators, bridging the gap between gust and standard Go.
- π Complete API documentation
- π‘ Rich examples for every feature
- π Active issue tracking
- π¬ Community discussions
- π Full Documentation - Complete API reference
- π‘ Examples - Comprehensive examples by feature
- π δΈζζζ‘£ - Chinese documentation
- π Issue Tracker - Report bugs or request features
- π¬ Discussions - Ask questions and share ideas
- Go 1.24+ (required for generics and standard iterator support)
We welcome contributions! Whether you're:
- π Reporting bugs - Help us improve
- π‘ Suggesting features - Share your ideas
- π Improving docs - Make documentation better
- π§ Submitting PRs - Contribute code improvements
Every contribution makes gust better!
# Clone the repository
git clone https://github.com/andeya/gust.git
cd gust
# Run tests
go test ./...
# Run tests with coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.outThis project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ for the Go community
Inspired by Rust's Result, Option, and Iterator traits
β Star us on GitHub β’ π Documentation β’ π Report Bug β’ π‘ Request Feature