From c5a9838733559f488447f259544911263aff879e Mon Sep 17 00:00:00 2001 From: Dmitry Kolesnikov Date: Thu, 31 Oct 2024 21:19:00 +0200 Subject: [PATCH 1/2] automatic BiMap for superset category --- optics/iso.go | 56 ++++++++++++++++++++++++++++++++++++ optics/iso_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++ optics/version.go | 2 +- 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/optics/iso.go b/optics/iso.go index 5b608cd..6623792 100644 --- a/optics/iso.go +++ b/optics/iso.go @@ -52,6 +52,62 @@ type codec[S, A, B any] struct { func (c codec[S, A, B]) Put(s *S, b B) *S { return c.lens.Put(s, c.cmap(b)) } func (c codec[S, A, B]) Get(s *S) B { return c.fmap(c.lens.Get(s)) } +// Automatic transformer for string superset, preserve mapping between +// two categories A, B, where both rooted to strings +func BiMapS[S any, A, B String](attr ...string) Lens[S, B] { + return BiMap( + ForProduct1[S, A](attr...), + func(a A) B { return B(a) }, + func(b B) A { return A(b) }, + ) +} + +type String interface { + ~string +} + +// Automatic transformer for []byte superset, preserve mapping between +// two categories A, B, where both rooted to []byte +func BiMapB[S any, A, B Byte](attr ...string) Lens[S, B] { + return BiMap( + ForProduct1[S, A](attr...), + func(a A) B { return B(a) }, + func(b B) A { return A(b) }, + ) +} + +type Byte interface { + ~[]byte +} + +// Automatic transformer for int superset, preserve mapping between +// two categories A, B, where both rooted to int +func BiMapI[S any, A, B Int](attr ...string) Lens[S, B] { + return BiMap( + ForProduct1[S, A](attr...), + func(a A) B { return B(a) }, + func(b B) A { return A(b) }, + ) +} + +type Int interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// Automatic transformer for float32 superset, preserve mapping between +// two categories A, B, where both rooted to float +func BiMapF[S any, A, B Float](attr ...string) Lens[S, B] { + return BiMap( + ForProduct1[S, A](attr...), + func(a A) B { return B(a) }, + func(b B) A { return A(b) }, + ) +} + +type Float interface { + ~float32 | ~float64 +} + // An isomorphism is a structure-preserving mapping between two structures // of the same shape that can be reversed by an inverse mapping. type Isomorphism[S, T any] interface { diff --git a/optics/iso_test.go b/optics/iso_test.go index bf133c8..d88df90 100644 --- a/optics/iso_test.go +++ b/optics/iso_test.go @@ -194,3 +194,74 @@ func TestIsomorphism(t *testing.T) { t.Run("Interface", testIsomorphism[io.Reader](&bytes.Buffer{})) } + +func TestBiMapX(t *testing.T) { + t.Run("String", func(t *testing.T) { + type A string + type B string + type S struct{ A } + + bimap := optics.BiMapS[S, A, B]() + + s := S{} + bimap.Put(&s, "some") + b := bimap.Get(&s) + + it.Then(t).Should( + it.Equal(b, "some"), + it.Equal(s.A, "some"), + ) + }) + + t.Run("Byte", func(t *testing.T) { + type A []byte + type B []byte + type S struct{ A } + + bimap := optics.BiMapB[S, A, B]() + + s := S{} + bimap.Put(&s, []byte("some")) + b := bimap.Get(&s) + + it.Then(t).Should( + it.Equiv(b, []byte("some")), + it.Equiv(s.A, []byte("some")), + ) + }) + + t.Run("Int", func(t *testing.T) { + type A int + type B int + type S struct{ A } + + bimap := optics.BiMapI[S, A, B]() + + s := S{} + bimap.Put(&s, 100) + b := bimap.Get(&s) + + it.Then(t).Should( + it.Equal(b, 100), + it.Equal(s.A, 100), + ) + }) + + t.Run("Float", func(t *testing.T) { + type A float64 + type B float64 + type S struct{ A } + + bimap := optics.BiMapF[S, A, B]() + + s := S{} + bimap.Put(&s, 100.0) + b := bimap.Get(&s) + + it.Then(t).Should( + it.Equal(b, 100.0), + it.Equal(s.A, 100.0), + ) + }) + +} diff --git a/optics/version.go b/optics/version.go index 92aa649..3abf827 100644 --- a/optics/version.go +++ b/optics/version.go @@ -8,4 +8,4 @@ package optics -const Version = "optics/v0.12.1" +const Version = "optics/v0.13.0" From a0e55e83d6ce7da7aa94533039140bb6b9ab5070 Mon Sep 17 00:00:00 2001 From: Dmitry Kolesnikov Date: Thu, 31 Oct 2024 21:22:16 +0200 Subject: [PATCH 2/2] update README --- optics/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/optics/README.md b/optics/README.md index 7c885af..8a3cc1b 100644 --- a/optics/README.md +++ b/optics/README.md @@ -106,6 +106,8 @@ See runnable examples to play with the library * optics/v0.10 and earlier uses `reflect` * optics/v0.11 and later uses `unsafe` pointers +* optics/v0.12 `isomorphism` +* optics/v0.13 auto `bimap` for superset category ## References