introduce pkg/strongunits

podman could benefit from stronger typing with some of our methods and
functions where uint64s, for example, are used because the unit of
measurement is unknown.  Also, the need to convert between storage units
is critical in podman and this package supports easy conversion as
needed.

to start, we implement the storage units (bytes, KiB, MiB, and GiB)
only.

Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
Brent Baude
2023-09-20 11:19:41 -05:00
parent 370937d6c1
commit eb9283c6fd
2 changed files with 253 additions and 0 deletions

65
pkg/strongunits/config.go Normal file
View File

@ -0,0 +1,65 @@
package strongunits
// supported units
// B represents bytes
type B uint64
// KiB represents KiB
type KiB uint64
// MiB represents MiB
type MiB uint64
// GiB represents GiB
type GiB uint64
const (
// kibToB is the math convert from bytes to KiB
kibToB = 1 << 10
// mibToB is the math to convert from bytes to MiB
mibToB = 1 << 20
// gibToB s the math to convert from bytes to GiB
gibToB = 1 << 30
)
// StorageUnits is an interface for converting disk/memory storage
// units amongst each other.
type StorageUnits interface {
ToBytes() B
}
// ToBytes is a pass-through function for bytes
func (b B) ToBytes() B {
return b
}
// ToBytes converts KiB to bytes
func (k KiB) ToBytes() B {
return B(k * kibToB)
}
// ToBytes converts MiB to bytes
func (m MiB) ToBytes() B {
return B(m * mibToB)
}
// ToBytes converts GiB to bytes
func (g GiB) ToBytes() B {
return B(g * gibToB)
}
// ToKiB converts any StorageUnit type to KiB
func ToKiB(b StorageUnits) KiB {
return KiB(b.ToBytes() >> 10)
}
// ToMib converts any StorageUnit type to MiB
func ToMib(b StorageUnits) MiB {
return MiB(b.ToBytes() >> 20)
}
// ToGiB converts any StorageUnit type to GiB
func ToGiB(b StorageUnits) GiB {
return GiB(b.ToBytes() >> 30)
}

View File

@ -0,0 +1,188 @@
package strongunits
import "testing"
func TestGiB_toBytes(t *testing.T) {
tests := []struct {
name string
g GiB
want B
}{
{
name: "good-1",
g: 1,
want: 1073741824,
},
{
name: "good-2",
g: 2,
want: 2147483648,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.g.ToBytes(); got != tt.want {
t.Errorf("ToBytes() = %v, want %v", got, tt.want)
}
})
}
}
func TestKiB_toBytes(t *testing.T) {
tests := []struct {
name string
k KiB
want B
}{
{
name: "good-1",
k: 100,
want: 102400,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.k.ToBytes(); got != tt.want {
t.Errorf("ToBytes() = %v, want %v", got, tt.want)
}
})
}
}
func TestMiB_toBytes(t *testing.T) {
tests := []struct {
name string
m MiB
want B
}{
{
name: "good-1",
m: 1024,
want: 1073741824,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.m.ToBytes(); got != tt.want {
t.Errorf("ToBytes() = %v, want %v", got, tt.want)
}
})
}
}
func TestToGiB(t *testing.T) {
type args struct {
b StorageUnits
}
tests := []struct {
name string
args args
want GiB
}{
{
name: "bytes to gib",
args: args{B(5368709120)},
want: 5,
},
{
name: "kib to gib",
args: args{KiB(3145728 * 2)},
want: 6,
},
{
name: "mib to gib",
args: args{MiB(2048)},
want: 2,
},
{
name: "gib to gib",
args: args{GiB(2)},
want: 2,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ToGiB(tt.args.b); got != tt.want {
t.Errorf("ToGiB() = %v, want %v", got, tt.want)
}
})
}
}
func TestToKiB(t *testing.T) {
type args struct {
b StorageUnits
}
tests := []struct {
name string
args args
want KiB
}{
{
name: "bytes to kib",
args: args{B(1024)},
want: 1,
},
{
name: "mib to kib",
args: args{MiB(2)},
want: 2048,
},
{
name: "kib to kib",
args: args{KiB(800)},
want: 800,
},
{
name: "gib to mib",
args: args{GiB(3)},
want: 3145728,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ToKiB(tt.args.b); got != tt.want {
t.Errorf("ToKiB() = %v, want %v", got, tt.want)
}
})
}
}
func TestToMib(t *testing.T) {
type args struct {
b StorageUnits
}
tests := []struct {
name string
args args
want MiB
}{
{
name: "bytes to mib",
args: args{B(3145728)},
want: 3,
},
{
name: "kib to mib",
args: args{KiB(2048)},
want: 2,
},
{
name: "mib to mib",
args: args{MiB(2)},
want: 2,
},
{
name: "gib to mib",
args: args{GiB(3)},
want: 3072,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ToMib(tt.args.b); got != tt.want {
t.Errorf("ToMib() = %v, want %v", got, tt.want)
}
})
}
}