typetui 0.2.0

A terminal-based typing test.
Documentation
package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

func RunWorkers(n int) {
    var wg sync.WaitGroup
    
    for i := 0; i < n; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Worker %d starting\n", id)
            time.Sleep(100 * time.Millisecond)
            fmt.Printf("Worker %d done\n", id)
        }(i)
    }
    
    wg.Wait()
}

func ProduceConsume() {
    ch := make(chan int, 10)
    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
            fmt.Println("Produced:", i)
        }
        close(ch)
    }()
    
    for val := range ch {
        fmt.Println("Consumed:", val)
    }
}

func WorkerPool(jobs []int, workers int) []int {
    jobCh := make(chan int, len(jobs))
    resultCh := make(chan int, len(jobs))
    var wg sync.WaitGroup
    for w := 0; w < workers; w++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for job := range jobCh {
                result := job * job
                resultCh <- result
            }
        }()
    }
    
    go func() {
        for _, job := range jobs {
            jobCh <- job
        }
        close(jobCh)
    }()
    
    go func() {
        wg.Wait()
        close(resultCh)
    }()
    
    var results []int
    for r := range resultCh {
        results = append(results, r)
    }
    return results
}

func SelectDemo() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(100 * time.Millisecond)
        ch1 <- "from ch1"
    }()
    
    go func() {
        time.Sleep(200 * time.Millisecond)
        ch2 <- "from ch2"
    }()
    
    select {
    case msg1 := <-ch1:
        fmt.Println(msg1)
    case msg2 := <-ch2:
        fmt.Println(msg2)
    case <-time.After(300 * time.Millisecond):
        fmt.Println("timeout")
    }
}

type Result struct {
    Value int
    Error error
}

func ProcessWithTimeout(ctx context.Context, items []int) ([]Result, error) {
    results := make([]Result, len(items))
    for i, item := range items {
        select {
        case <-ctx.Done():
            return results, ctx.Err()
        default:
            time.Sleep(50 * time.Millisecond)
            results[i] = Result{Value: item * 2}
        }
    }
    return results, nil
}

func Generator(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

func Square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

func Merge(chans ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int)
    
    output := func(c <-chan int) {
        defer wg.Done()
        for n := range c {
            out <- n
        }
    }
    
    wg.Add(len(chans))
    for _, c := range chans {
        go output(c)
    }
    
    go func() {
        wg.Wait()
        close(out)
    }()
    
    return out
}

type SafeCounter struct {
    mu    sync.RWMutex
    count map[string]int
}

func NewSafeCounter() *SafeCounter {
    return &SafeCounter{
        count: make(map[string]int),
    }
}

func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count[key]++
}

func (c *SafeCounter) Get(key string) int {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.count[key]
}

type Singleton struct {
    value string
}

var (
    instance *Singleton
    once     sync.Once
)

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{value: "initialized"}
    })
    return instance
}

func main() {
    jobs := []int{1, 2, 3, 4, 5}
    results := WorkerPool(jobs, 3)
    fmt.Println("Results:", results)
    nums := Generator(1, 2, 3, 4, 5)
    squares := Square(nums)
    for n := range squares {
        fmt.Println("Square:", n)
    }
    ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
    defer cancel()
    
    items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    res, err := ProcessWithTimeout(ctx, items)
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Println("Processed:", len(res))
}