139 lines
2.4 KiB
Go
139 lines
2.4 KiB
Go
package aoc
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"iter"
|
|
)
|
|
|
|
func SplitComma(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|
if atEOF && len(data) == 0 {
|
|
return 0, nil, nil
|
|
}
|
|
if i := bytes.IndexByte(data, ','); i >= 0 {
|
|
return i + 1, data[0:i], nil
|
|
}
|
|
if atEOF {
|
|
return len(data), data, nil
|
|
}
|
|
return 0, nil, nil
|
|
}
|
|
|
|
func SplitString(s string) bufio.SplitFunc {
|
|
sep := []byte(s)
|
|
return func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|
if atEOF && len(data) == 0 {
|
|
return 0, nil, nil
|
|
}
|
|
if i := bytes.Index(data, sep); i >= 0 {
|
|
return i + len(sep), data[0:i], nil
|
|
}
|
|
if atEOF {
|
|
return len(data), data, nil
|
|
}
|
|
return 0, nil, nil
|
|
}
|
|
}
|
|
|
|
func ReadString(r io.Reader) (string, error) {
|
|
buff, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(buff), nil
|
|
}
|
|
|
|
type Logger interface {
|
|
Printf(string, ...interface{})
|
|
Println(...interface{})
|
|
}
|
|
|
|
type Context struct {
|
|
Body io.Reader
|
|
Logger Logger
|
|
Context context.Context
|
|
}
|
|
|
|
func (c *Context) Scanner(split ...bufio.SplitFunc) *bufio.Scanner {
|
|
s := bufio.NewScanner(c.Body)
|
|
if len(split) == 1 {
|
|
s.Split(split[0])
|
|
}
|
|
if len(split) > 2 {
|
|
panic("too many split line handlers")
|
|
}
|
|
return s
|
|
}
|
|
func (c *Context) BodyString() (string, error) {
|
|
return ReadString(c.Body)
|
|
}
|
|
func (c *Context) BodyBytes() ([]byte, error) {
|
|
return io.ReadAll(c.Body)
|
|
}
|
|
|
|
func (c *Context) Printf(format string, args ...interface{}) {
|
|
if c.Logger != nil {
|
|
c.Logger.Printf(format, args...)
|
|
}
|
|
}
|
|
func (c *Context) Println(args ...interface{}) {
|
|
if c.Logger != nil {
|
|
c.Logger.Println(args...)
|
|
}
|
|
}
|
|
|
|
type CustomScanner[T scannable, K any] struct {
|
|
val K
|
|
err error
|
|
|
|
inner scannable
|
|
mapFunc func(T) (K, error)
|
|
}
|
|
|
|
func (s *CustomScanner[T, K]) From(t T) {
|
|
s.inner = t
|
|
}
|
|
func (s *CustomScanner[T, K]) MapFunc(f func(t T) (K, error)) {
|
|
s.mapFunc = f
|
|
}
|
|
|
|
func (s *CustomScanner[T, K]) Value() K {
|
|
return s.val
|
|
}
|
|
func (s *CustomScanner[T, K]) Values() iter.Seq[K] {
|
|
return func(yield func(K) bool) {
|
|
for s.Scan() {
|
|
if !yield(s.Value()) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type scannable interface {
|
|
Scan() bool
|
|
}
|
|
|
|
func (s *CustomScanner[T, K]) Scan() bool {
|
|
if s.err != nil {
|
|
return false
|
|
}
|
|
|
|
if !s.inner.Scan() {
|
|
return false
|
|
}
|
|
|
|
s.val, s.err = s.mapFunc(s.inner.(T))
|
|
if s.err != nil {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (s *CustomScanner[T, K]) Err() error {
|
|
return s.err
|
|
}
|