From cdc65f9e8de256918af833aaee97588861fd6aa5 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sun, 7 Jun 2026 06:01:13 +0000 Subject: *: Refactor file granularity --- config/char.go | 28 ++++++++ config/convert.go | 109 ++++++++++++++++++++++++++++ config/kind.go | 161 ------------------------------------------ config/section.go | 15 ++++ config/value.go | 10 +++ object/blob/blob.go | 7 +- object/blob/doc.go | 4 ++ object/commit/commit.go | 6 ++ object/commit/extraheader.go | 7 -- object/signature/signature.go | 9 +++ object/signature/when.go | 10 --- 11 files changed, 183 insertions(+), 183 deletions(-) create mode 100644 config/convert.go create mode 100644 object/blob/doc.go delete mode 100644 object/commit/extraheader.go delete mode 100644 object/signature/when.go diff --git a/config/char.go b/config/char.go index a282b49d..3f78723e 100644 --- a/config/char.go +++ b/config/char.go @@ -106,3 +106,31 @@ func (p *configParser) skipBOM() error { return nil } + +func isKeyChar(ch byte) bool { + return isLetter(ch) || isDigit(ch) || ch == '-' +} + +func isSpace(ch byte) bool { + return ch == ' ' || ch == '\t' +} + +func isWhitespace(ch byte) bool { + return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f' +} + +func isLetter(ch byte) bool { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') +} + +func isDigit(ch byte) bool { + return ch >= '0' && ch <= '9' +} + +func toLower(ch byte) byte { + if ch >= 'A' && ch <= 'Z' { + return ch + ('a' - 'A') + } + + return ch +} diff --git a/config/convert.go b/config/convert.go new file mode 100644 index 00000000..92148394 --- /dev/null +++ b/config/convert.go @@ -0,0 +1,109 @@ +package config + +import ( + "fmt" + "math" + "strconv" + "strings" + + "lindenii.org/go/lgo/intconv" +) + +func parseBool(value string) (bool, error) { + switch { + case strings.EqualFold(value, "true"), + strings.EqualFold(value, "yes"), + strings.EqualFold(value, "on"): + return true, nil + case strings.EqualFold(value, "false"), + strings.EqualFold(value, "no"), + strings.EqualFold(value, "off"), + value == "": + return false, nil + } + + n, err := parseInt32(value) + if err != nil { + return false, err + } + + return n != 0, nil +} + +func parseInt32(value string) (int32, error) { + n64, err := parseInt64WithMax(value, math.MaxInt32) + if err != nil { + return 0, err + } + + n32, err := intconv.Int64ToInt32(n64) + if err != nil { + return 0, fmt.Errorf("%w: %q", ErrValueRange, value) + } + + return n32, nil +} + +func parseInt(value string) (int, error) { + n64, err := parseInt64WithMax(value, int64(int(^uint(0)>>1))) + if err != nil { + return 0, err + } + + return int(n64), nil +} + +func parseInt64(value string) (int64, error) { + return parseInt64WithMax(value, int64(^uint64(0)>>1)) +} + +func parseInt64WithMax(value string, maxValue int64) (int64, error) { + if value == "" { + return 0, ErrValueEmpty + } + + trimmed := strings.TrimLeft(value, " \t\n\r\f\v") + if trimmed == "" { + return 0, fmt.Errorf("%w: %q", ErrValueEmpty, value) + } + + numPart := trimmed + factor := int64(1) + + if last := trimmed[len(trimmed)-1]; last == 'k' || last == 'K' || last == 'm' || last == 'M' || last == 'g' || last == 'G' { + switch toLower(last) { + case 'k': + factor = 1024 + case 'm': + factor = 1024 * 1024 + case 'g': + factor = 1024 * 1024 * 1024 + } + + numPart = trimmed[:len(trimmed)-1] + } + + if numPart == "" { + return 0, fmt.Errorf("%w: %q", ErrValueSyntax, value) + } + + n, err := strconv.ParseInt(numPart, 0, 64) + if err != nil { + return 0, fmt.Errorf("%w: %q: %w", ErrValueSyntax, value, err) + } + + intMax := maxValue + intMin := -maxValue - 1 + + if n > 0 && n > intMax/factor { + return 0, fmt.Errorf("%w: %q", ErrValueRange, value) + } + + if n < 0 && n < intMin/factor { + return 0, fmt.Errorf("%w: %q", ErrValueRange, value) + } + + n *= factor + + return n, nil +} diff --git a/config/kind.go b/config/kind.go index cf87a348..01d325ec 100644 --- a/config/kind.go +++ b/config/kind.go @@ -1,14 +1,5 @@ package config -import ( - "fmt" - "math" - "strconv" - "strings" - - "lindenii.org/go/lgo/intconv" -) - // Kind describes the presence and form of a config value. type Kind uint8 @@ -22,155 +13,3 @@ const ( // KindString means the key exists and has an explicit value (possibly ""). KindString ) - -func isValidSection(s string) bool { - if len(s) == 0 { - return false - } - - for i := range len(s) { - ch := s[i] - if !isLetter(ch) && !isDigit(ch) && ch != '-' && ch != '.' { - return false - } - } - - return true -} - -func isKeyChar(ch byte) bool { - return isLetter(ch) || isDigit(ch) || ch == '-' -} - -func parseBool(value string) (bool, error) { - switch { - case strings.EqualFold(value, "true"), - strings.EqualFold(value, "yes"), - strings.EqualFold(value, "on"): - return true, nil - case strings.EqualFold(value, "false"), - strings.EqualFold(value, "no"), - strings.EqualFold(value, "off"), - value == "": - return false, nil - } - - n, err := parseInt32(value) - if err != nil { - return false, err - } - - return n != 0, nil -} - -func parseInt32(value string) (int32, error) { - n64, err := parseInt64WithMax(value, math.MaxInt32) - if err != nil { - return 0, err - } - - n32, err := intconv.Int64ToInt32(n64) - if err != nil { - return 0, fmt.Errorf("%w: %q", ErrValueRange, value) - } - - return n32, nil -} - -func parseInt(value string) (int, error) { - n64, err := parseInt64WithMax(value, int64(int(^uint(0)>>1))) - if err != nil { - return 0, err - } - - return int(n64), nil -} - -func parseInt64(value string) (int64, error) { - return parseInt64WithMax(value, int64(^uint64(0)>>1)) -} - -func parseInt64WithMax(value string, maxValue int64) (int64, error) { - if value == "" { - return 0, ErrValueEmpty - } - - trimmed := strings.TrimLeft(value, " \t\n\r\f\v") - if trimmed == "" { - return 0, fmt.Errorf("%w: %q", ErrValueEmpty, value) - } - - numPart := trimmed - factor := int64(1) - - if last := trimmed[len(trimmed)-1]; last == 'k' || last == 'K' || last == 'm' || last == 'M' || last == 'g' || last == 'G' { - switch toLower(last) { - case 'k': - factor = 1024 - case 'm': - factor = 1024 * 1024 - case 'g': - factor = 1024 * 1024 * 1024 - } - - numPart = trimmed[:len(trimmed)-1] - } - - if numPart == "" { - return 0, fmt.Errorf("%w: %q", ErrValueSyntax, value) - } - - n, err := strconv.ParseInt(numPart, 0, 64) - if err != nil { - return 0, fmt.Errorf("%w: %q: %w", ErrValueSyntax, value, err) - } - - intMax := maxValue - intMin := -maxValue - 1 - - if n > 0 && n > intMax/factor { - return 0, fmt.Errorf("%w: %q", ErrValueRange, value) - } - - if n < 0 && n < intMin/factor { - return 0, fmt.Errorf("%w: %q", ErrValueRange, value) - } - - n *= factor - - return n, nil -} - -func truncateAtNUL(value string) string { - for i := range len(value) { - if value[i] == 0 { - return value[:i] - } - } - - return value -} - -func isSpace(ch byte) bool { - return ch == ' ' || ch == '\t' -} - -func isWhitespace(ch byte) bool { - return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f' -} - -func isLetter(ch byte) bool { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') -} - -func isDigit(ch byte) bool { - return ch >= '0' && ch <= '9' -} - -func toLower(ch byte) byte { - if ch >= 'A' && ch <= 'Z' { - return ch + ('a' - 'A') - } - - return ch -} diff --git a/config/section.go b/config/section.go index 667ef00e..fd06eee4 100644 --- a/config/section.go +++ b/config/section.go @@ -44,3 +44,18 @@ func (p *configParser) parseSection() error { name.WriteByte(toLower(ch)) } } + +func isValidSection(s string) bool { + if len(s) == 0 { + return false + } + + for i := range len(s) { + ch := s[i] + if !isLetter(ch) && !isDigit(ch) && ch != '-' && ch != '.' { + return false + } + } + + return true +} diff --git a/config/value.go b/config/value.go index 443d4e5b..851d0241 100644 --- a/config/value.go +++ b/config/value.go @@ -109,3 +109,13 @@ func (p *configParser) parseValue() (string, error) { value.WriteByte(ch) } } + +func truncateAtNUL(value string) string { + for i := range len(value) { + if value[i] == 0 { + return value[:i] + } + } + + return value +} diff --git a/object/blob/blob.go b/object/blob/blob.go index 4ba132d1..793935fe 100644 --- a/object/blob/blob.go +++ b/object/blob/blob.go @@ -1,13 +1,10 @@ -// Package blob provides -// representations, parsers, and serializers -// for blob objects. package blob // Blob represents a Git blob object. // // Blob is fully materialized in memory. -// Consider using objectstore.Reader.ReadReaderContent, -// or appropriate streaming write APIs. +// Consider using [lindenii.org/go/furgit/object/fetch] +// for streaming access, or appropriate streaming write APIs. // // Labels: MT-Unsafe. type Blob struct { diff --git a/object/blob/doc.go b/object/blob/doc.go new file mode 100644 index 00000000..8eea353e --- /dev/null +++ b/object/blob/doc.go @@ -0,0 +1,4 @@ +// Package blob provides +// representations, parsers, and serializers +// for blob objects. +package blob diff --git a/object/commit/commit.go b/object/commit/commit.go index f41366b7..6a89bce9 100644 --- a/object/commit/commit.go +++ b/object/commit/commit.go @@ -17,3 +17,9 @@ type Commit struct { ChangeID string ExtraHeaders []ExtraHeader } + +// ExtraHeader represents an extra header in a Git object. +type ExtraHeader struct { + Key string + Value []byte +} diff --git a/object/commit/extraheader.go b/object/commit/extraheader.go deleted file mode 100644 index 79d4f9cc..00000000 --- a/object/commit/extraheader.go +++ /dev/null @@ -1,7 +0,0 @@ -package commit - -// ExtraHeader represents an extra header in a Git object. -type ExtraHeader struct { - Key string - Value []byte -} diff --git a/object/signature/signature.go b/object/signature/signature.go index e9ec56c0..3d5b911f 100644 --- a/object/signature/signature.go +++ b/object/signature/signature.go @@ -1,5 +1,7 @@ package signature +import "time" + // Signature represents a Git signature (author/committer/tagger). // // Labels: MT-Unsafe. @@ -9,3 +11,10 @@ type Signature struct { WhenUnix int64 OffsetMinutes int32 } + +// When returns a time.Time with the signature's timezone offset. +func (signature Signature) When() time.Time { + loc := time.FixedZone("git", int(signature.OffsetMinutes)*60) + + return time.Unix(signature.WhenUnix, 0).In(loc) +} diff --git a/object/signature/when.go b/object/signature/when.go deleted file mode 100644 index 0a252f68..00000000 --- a/object/signature/when.go +++ /dev/null @@ -1,10 +0,0 @@ -package signature - -import "time" - -// When returns a time.Time with the signature's timezone offset. -func (signature Signature) When() time.Time { - loc := time.FixedZone("git", int(signature.OffsetMinutes)*60) - - return time.Unix(signature.WhenUnix, 0).In(loc) -} -- cgit v1.3.1-10-gc9f91