Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add timezone location support #2705

Merged
merged 4 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions gnovm/stdlibs/generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,40 @@ var nativeFuncs = [...]NativeFunc{
))
},
},
{
"time",
"loadFromEmbeddedTZData",
[]gno.FieldTypeExpr{
{Name: gno.N("p0"), Type: gno.X("string")},
},
[]gno.FieldTypeExpr{
{Name: gno.N("r0"), Type: gno.X("[]byte")},
{Name: gno.N("r1"), Type: gno.X("bool")},
},
false,
func(m *gno.Machine) {
b := m.LastBlock()
var (
p0 string
rp0 = reflect.ValueOf(&p0).Elem()
)

gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0)

r0, r1 := libs_time.X_loadFromEmbeddedTZData(p0)

m.PushValue(gno.Go2GnoValue(
m.Alloc,
m.Store,
reflect.ValueOf(&r0).Elem(),
))
m.PushValue(gno.Go2GnoValue(
m.Alloc,
m.Store,
reflect.ValueOf(&r1).Elem(),
))
},
},
}

var initOrder = [...]string{
Expand Down
50 changes: 15 additions & 35 deletions gnovm/stdlibs/time/timezoneinfo.gno
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@ var errLocation = errors.New("time: invalid location name")

var zoneinfo *string

func loadFromEmbeddedTZData(name string) ([]byte, bool) // injected

// XXX var zoneinfoOnce sync.Once

// LoadLocation returns the Location with the given name.
Expand All @@ -640,41 +642,19 @@ var zoneinfo *string
// - $GOROOT/lib/time/zoneinfo.zip
// - the time/tzdata package, if it was imported
func LoadLocation(name string) (*Location, error) {
panic("XXX LoadLocation not yet implemented")
/*
if name == "" || name == "UTC" {
return UTC, nil
}
if name == "Local" {
return Local, nil
}
if containsDotDot(name) || name[0] == '/' || name[0] == '\\' {
// No valid IANA Time Zone name contains a single dot,
// much less dot dot. Likewise, none begin with a slash.
return nil, errLocation
}
zoneinfoOnce.Do(func() {
env, _ := syscall.Getenv("ZONEINFO")
zoneinfo = &env
})
var firstErr error
if *zoneinfo != "" {
if zoneData, err := loadTzinfoFromDirOrZip(*zoneinfo, name); err == nil {
if z, err := LoadLocationFromTZData(name, zoneData); err == nil {
return z, nil
}
firstErr = err
} else if err != syscall.ENOENT {
firstErr = err
}
}
if z, err := loadLocation(name, platformZoneSources); err == nil {
return z, nil
} else if firstErr == nil {
firstErr = err
}
return nil, firstErr
*/
if name == "" || name == "UTC" {
return UTC, nil
}
if name == "Local" {
return Local, nil
}
if containsDotDot(name) || name[0] == '/' || name[0] == '\\' {
// No valid IANA Time Zone name contains a single dot,
// much less dot dot. Likewise, none begin with a slash.
return nil, errLocation
}

return loadLocation(name)
}

// containsDotDot reports whether s contains "..".
Expand Down
74 changes: 74 additions & 0 deletions gnovm/stdlibs/time/tzdata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package time

// locationDefinitions are loaded during initialization using modified code from:
// https://cs.opensource.google/go/go/+/refs/tags/go1.23.0:src/time/tzdata/tzdata.go
var locationDefinitions = make(map[string][]byte)

func init() {
const (
zecheader = 0x06054b50
zcheader = 0x02014b50
ztailsize = 22

zheadersize = 30
zheader = 0x04034b50
)

z := zipdata

idx := len(z) - ztailsize
n := get2s(z[idx+10:])
idx = get4s(z[idx+16:])

for i := 0; i < n; i++ {
// See time.loadTzinfoFromZip for zip entry layout.
if get4s(z[idx:]) != zcheader {
break

Check warning on line 26 in gnovm/stdlibs/time/tzdata.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/time/tzdata.go#L26

Added line #L26 was not covered by tests
}
meth := get2s(z[idx+10:])
size := get4s(z[idx+24:])
namelen := get2s(z[idx+28:])
xlen := get2s(z[idx+30:])
fclen := get2s(z[idx+32:])
off := get4s(z[idx+42:])
zname := z[idx+46 : idx+46+namelen]
idx += 46 + namelen + xlen + fclen

if meth != 0 {
panic("unsupported compression for " + zname + " in embedded tzdata")

Check warning on line 38 in gnovm/stdlibs/time/tzdata.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/time/tzdata.go#L38

Added line #L38 was not covered by tests
}

// See time.loadTzinfoFromZip for zip per-file header layout.
nidx := off
if get4s(z[nidx:]) != zheader ||
get2s(z[nidx+8:]) != meth ||
get2s(z[nidx+26:]) != namelen {
panic("corrupt embedded tzdata")

Check warning on line 46 in gnovm/stdlibs/time/tzdata.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/time/tzdata.go#L46

Added line #L46 was not covered by tests
}

nxlen := get2s(z[nidx+28:])
nidx += 30 + namelen + nxlen
locationDefinitions[zname] = []byte(z[nidx : nidx+size])
}
}

// get4s returns the little-endian 32-bit value at the start of s.
func get4s(s string) int {
if len(s) < 4 {
return 0

Check warning on line 58 in gnovm/stdlibs/time/tzdata.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/time/tzdata.go#L58

Added line #L58 was not covered by tests
}
return int(s[0]) | int(s[1])<<8 | int(s[2])<<16 | int(s[3])<<24
}

// get2s returns the little-endian 16-bit value at the start of s.
func get2s(s string) int {
if len(s) < 2 {
return 0

Check warning on line 66 in gnovm/stdlibs/time/tzdata.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/time/tzdata.go#L66

Added line #L66 was not covered by tests
}
return int(s[0]) | int(s[1])<<8
}

func X_loadFromEmbeddedTZData(name string) ([]byte, bool) {
definition, ok := locationDefinitions[name]
return definition, ok
}
Loading
Loading