Skip to content

Commit

Permalink
introduce pkg/strongunits
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
baude committed Sep 20, 2023
1 parent 370937d commit eb9283c
Show file tree
Hide file tree
Showing 2 changed files with 253 additions and 0 deletions.
65 changes: 65 additions & 0 deletions pkg/strongunits/config.go
Original file line number Diff line number Diff line change
@@ -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)
}
188 changes: 188 additions & 0 deletions pkg/strongunits/config_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}

0 comments on commit eb9283c

Please sign in to comment.