package main

import (
	"bytes"
	"fmt"
	"sync"
	"sync/atomic"
)

type Counter struct {
	mu sync.Mutex
	n  int
}

func (c *Counter) Add()       { c.mu.Lock(); defer c.mu.Unlock(); c.n++ }
func (c *Counter) Value() int { c.mu.Lock(); defer c.mu.Unlock(); return c.n }

// Mailbox has one consumer and is closed after its last Send.
type Mailbox struct {
	mu     sync.Mutex
	ready  *sync.Cond
	queue  []int
	closed bool
}

func NewMailbox() *Mailbox {
	m := &Mailbox{}
	m.ready = sync.NewCond(&m.mu)
	return m
}
func (m *Mailbox) Send(n int) {
	m.mu.Lock()
	defer m.mu.Unlock()
	if m.closed {
		panic("send after mailbox close")
	}
	m.queue = append(m.queue, n)
	m.ready.Signal()
}
func (m *Mailbox) Close() {
	m.mu.Lock()
	m.closed = true
	m.ready.Broadcast()
	m.mu.Unlock()
}
func (m *Mailbox) Receive() (int, bool) {
	m.mu.Lock()
	defer m.mu.Unlock()
	for len(m.queue) == 0 && !m.closed {
		m.ready.Wait()
	}
	if len(m.queue) == 0 {
		return 0, false
	}
	n := m.queue[0]
	m.queue = m.queue[1:]
	return n, true
}

func Count(n int) int {
	var c Counter
	var wg sync.WaitGroup
	for range n {
		wg.Go(c.Add)
	} // Go 1.25+; callback must not panic.
	wg.Wait()
	return c.Value()
}
func main() {
	fmt.Println("counter:", Count(100))
	initCount := 0
	config := sync.OnceValue(func() string { initCount++; return "ready" })
	fmt.Println(config(), config(), "initializations:", initCount)
	var completed atomic.Int64
	completed.Add(1)
	fmt.Println("atomic:", completed.Load())
	pool := sync.Pool{New: func() any { return new(bytes.Buffer) }}
	buf := pool.Get().(*bytes.Buffer)
	buf.Reset()
	buf.WriteString("temporary")
	fmt.Println(buf.String())
	buf.Reset()
	pool.Put(buf) // No use of buf after ownership is returned.
	var cache sync.Map
	a, loadedA := cache.LoadOrStore("key", 7)
	b, loadedB := cache.LoadOrStore("key", 9)
	fmt.Println("map:", a, loadedA, b, loadedB)
	m := NewMailbox()
	var wg sync.WaitGroup
	wg.Go(func() { m.Send(7); m.Close() })
	n, ok := m.Receive()
	_, more := m.Receive()
	wg.Wait()
	fmt.Println("mailbox:", n, ok, more)
}
