From e0bc7fd82a8284dbee8c3c379fb85e00153a7d31 Mon Sep 17 00:00:00 2001 From: mleku Date: Sun, 2 Feb 2025 19:54:19 -0106 Subject: [PATCH] create URL codec --- pkg/url/log.go | 9 +++++++++ pkg/url/url.go | 46 +++++++++++++++++++++++++++++++++++++++++++++ pkg/url/url_test.go | 29 ++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 pkg/url/log.go create mode 100644 pkg/url/url.go create mode 100644 pkg/url/url_test.go diff --git a/pkg/url/log.go b/pkg/url/log.go new file mode 100644 index 0000000..8b7011e --- /dev/null +++ b/pkg/url/log.go @@ -0,0 +1,9 @@ +package url + +import ( + "protocol.realy.lol/pkg/lol" +) + +var ( + log, chk, errorf = lol.Main.Log, lol.Main.Check, lol.Main.Errorf +) diff --git a/pkg/url/url.go b/pkg/url/url.go new file mode 100644 index 0000000..4574f3f --- /dev/null +++ b/pkg/url/url.go @@ -0,0 +1,46 @@ +package url + +import ( + "bytes" + "net/url" +) + +type U struct{ uu []byte } + +// New creates a new URL codec.C from the provided URL, and validates it. +func New[V ~string | []byte](ur V) (uu *U, err error) { + uu = new(U) + var UU *url.URL + if UU, err = url.Parse(string(ur)); chk.E(err) { + return + } else { + // if it is valid, store it + uu.uu = []byte(UU.String()) + } + return +} + +func (u *U) String() string { return string(u.uu) } +func (u *U) Bytes() []byte { return u.uu } +func (u *U) Equal(u2 *U) bool { return bytes.Equal(u.uu, u2.uu) } + +func (u *U) Marshal(dst []byte) (result []byte, err error) { + result = append(append(dst, u.uu...), '\n') + return +} + +func (u *U) Unmarshal(data []byte) (rem []byte, err error) { + rem = data + for i, v := range rem { + if v == '\n' { + u.uu = rem[:i] + rem = rem[i+1:] + break + } + } + // validate the URL and return error if not valid. + if _, err = url.Parse(string(u.uu)); chk.E(err) { + return + } + return +} diff --git a/pkg/url/url_test.go b/pkg/url/url_test.go new file mode 100644 index 0000000..7abca84 --- /dev/null +++ b/pkg/url/url_test.go @@ -0,0 +1,29 @@ +package url + +import ( + "testing" +) + +func TestU_Marshal_Unmarshal(t *testing.T) { + u := "https://example.com/path/to/resource" + var err error + var u1 *U + if u1, err = New(u); chk.E(err) { + t.Fatal(err) + } + var m1 []byte + if m1, err = u1.Marshal(nil); chk.E(err) { + t.Fatal(err) + } + u2 := new(U) + var rem []byte + if rem, err = u2.Unmarshal(m1); chk.E(err) { + t.Fatal(err) + } + if len(rem) > 0 { + t.Fatalf("'%s' should be empty", string(rem)) + } + if !u2.Equal(u1) { + t.Fatalf("u1 should be equal to u2: '%s' != '%s'", u1, u2) + } +}