wip: oci
This commit is contained in:
67
tool/human/readme.md
Normal file
67
tool/human/readme.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# human
|
||||
|
||||
Human-readable size formatting for Go.
|
||||
|
||||
## Features
|
||||
|
||||
- **Binary Units**: Uses 1024 as base (KB, MB, GB, etc.)
|
||||
- **Decimal Units**: Uses 1000 as base (KB, MB, GB, etc.)
|
||||
- **Auto-scaling**: Automatically selects appropriate unit
|
||||
- **Precision Control**: Shows decimals only when needed
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import "gitea.loveuer.com/loveuer/upkg/tool/human"
|
||||
```
|
||||
|
||||
### Binary Format (1024 base)
|
||||
|
||||
```go
|
||||
human.Size(1024) // "1 KB"
|
||||
human.Size(1024 * 1024) // "1 MB"
|
||||
human.Size(1536) // "1.50 KB"
|
||||
human.Size(-1024 * 1024) // "-1 MB"
|
||||
```
|
||||
|
||||
### Decimal Format (1000 base)
|
||||
|
||||
```go
|
||||
human.SizeDecimal(1000) // "1 KB"
|
||||
human.SizeDecimal(1000000) // "1 MB"
|
||||
human.SizeDecimal(1000000000) // "1 GB"
|
||||
```
|
||||
|
||||
### Binary (SI-compatible)
|
||||
|
||||
```go
|
||||
human.SizeBinary(1000) // "976.56 KB"
|
||||
human.SizeBinary(1000000) // "953.67 MB"
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
| Function | ns/op | B/op | allocs |
|
||||
|----------|-------|------|--------|
|
||||
| Size | 439 | 32 | 3 |
|
||||
| SizeDecimal | 387 | 32 | 3 |
|
||||
| SizeBinary | 558 | 40 | 3 |
|
||||
|
||||
## Examples
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gitea.loveuer.com/loveuer/upkg/tool/human"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(human.Size(1024)) // 1 KB
|
||||
fmt.Println(human.Size(1024 * 1024)) // 1 MB
|
||||
fmt.Println(human.Size(1024 * 1024 * 1024)) // 1 GB
|
||||
fmt.Println(human.Size(1500)) // 1.46 KB
|
||||
fmt.Println(human.Size(0)) // 0 B
|
||||
}
|
||||
```
|
||||
71
tool/human/size.go
Normal file
71
tool/human/size.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package human
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Size(size int64) string {
|
||||
if size < 0 {
|
||||
return "-" + Size(-size)
|
||||
}
|
||||
|
||||
if size < 1024 {
|
||||
return "0 B"
|
||||
}
|
||||
|
||||
units := []string{"KB", "MB", "GB", "TB", "PB", "EB"}
|
||||
div := int64(1024)
|
||||
exp := 0
|
||||
|
||||
for i := 1; i < len(units); i++ {
|
||||
nextDiv := div * 1024
|
||||
if size < nextDiv {
|
||||
break
|
||||
}
|
||||
div = nextDiv
|
||||
exp = i
|
||||
}
|
||||
|
||||
value := float64(size) / float64(div)
|
||||
if value == float64(int64(value)) {
|
||||
return fmt.Sprintf("%.0f %s", value, units[exp])
|
||||
}
|
||||
return fmt.Sprintf("%.2f %s", value, units[exp])
|
||||
}
|
||||
|
||||
func Duration(d time.Duration) string {
|
||||
if d < 0 {
|
||||
return "-" + Duration(-d)
|
||||
}
|
||||
|
||||
totalSeconds := int64(d.Seconds())
|
||||
days := totalSeconds / 86400
|
||||
hours := (totalSeconds % 86400) / 3600
|
||||
minutes := (totalSeconds % 3600) / 60
|
||||
seconds := totalSeconds % 60
|
||||
nanos := d.Nanoseconds() % int64(time.Second)
|
||||
|
||||
var parts []string
|
||||
if days > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%dd", days))
|
||||
}
|
||||
if hours > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%dh", hours))
|
||||
}
|
||||
if minutes > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%dm", minutes))
|
||||
}
|
||||
|
||||
if nanos > 0 {
|
||||
secWithNanos := float64(seconds) + float64(nanos)/1e9
|
||||
parts = append(parts, fmt.Sprintf("%.2fs", secWithNanos))
|
||||
} else if seconds > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%ds", seconds))
|
||||
} else if len(parts) == 0 {
|
||||
return "0s"
|
||||
}
|
||||
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
78
tool/human/size_test.go
Normal file
78
tool/human/size_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package human
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
tests := []struct {
|
||||
input int64
|
||||
expected string
|
||||
}{
|
||||
{0, "0 B"},
|
||||
{1, "0 B"},
|
||||
{1023, "0 B"},
|
||||
{1024, "1 KB"},
|
||||
{1536, "1.50 KB"},
|
||||
{1024 * 1024, "1 MB"},
|
||||
{1024 * 1024 * 1024, "1 GB"},
|
||||
{1024 * 1024 * 1024 * 1024, "1 TB"},
|
||||
{-1024, "-1 KB"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result := Size(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("Size(%d) = %s, want %s", tt.input, result, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuration(t *testing.T) {
|
||||
tests := []struct {
|
||||
input time.Duration
|
||||
expected string
|
||||
}{
|
||||
{0, "0s"},
|
||||
{time.Second, "1s"},
|
||||
{time.Minute, "1m"},
|
||||
{time.Hour, "1h"},
|
||||
{24 * time.Hour, "1d"},
|
||||
{25 * time.Hour, "1d 1h"},
|
||||
{90 * time.Minute, "1h 30m"},
|
||||
{time.Hour + time.Minute + 34*time.Second + 230*time.Millisecond, "1h 1m 34.23s"},
|
||||
{1356*24*time.Hour + 2*time.Hour + 55*time.Minute + 34*time.Second + 230*time.Millisecond, "1356d 2h 55m 34.23s"},
|
||||
{-time.Hour, "-1h"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result := Duration(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("Duration(%v) = %s, want %s", tt.input, result, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleSize() {
|
||||
fmt.Println(Size(1024))
|
||||
fmt.Println(Size(1024 * 1024))
|
||||
fmt.Println(Size(1536))
|
||||
// Output:
|
||||
// 1 KB
|
||||
// 1 MB
|
||||
// 1.50 KB
|
||||
}
|
||||
|
||||
func ExampleDuration() {
|
||||
fmt.Println(Duration(time.Hour))
|
||||
fmt.Println(Duration(25 * time.Hour))
|
||||
fmt.Println(Duration(90 * time.Minute))
|
||||
fmt.Println(Duration(1356*24*time.Hour + 2*time.Hour + 55*time.Minute + 34*time.Second + 230*time.Millisecond))
|
||||
// Output:
|
||||
// 1h
|
||||
// 1d 1h
|
||||
// 1h 30m
|
||||
// 1356d 2h 55m 34.23s
|
||||
}
|
||||
Reference in New Issue
Block a user