Skip to content

Commit 6b7ca6a

Browse files
Merge pull request disneystreaming#1873 from ghostbuster91/validated-prism
Add asSurjection to ValidatedNewtype
1 parent 06e6650 commit 6b7ca6a

File tree

4 files changed

+44
-2
lines changed

4 files changed

+44
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ When adding entries, please treat them as if they could end up in a release any
55

66
Thank you!
77

8+
# 0.18.47
9+
10+
* core: Add `asSurjection` method to `ValidatedNewtype` class (see [#1873](https://github.com/disneystreaming/smithy4s/pull/1873))
11+
812
# 0.18.46
913

1014
* core: Set the Accept header via the HttpUnaryClientCodecs (see [#1864](https://github.com/disneystreaming/smithy4s/pull/1864))

modules/bootstrapped/test/src/smithy4s/ValidatedNewtypesSpec.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,32 @@ class ValidatedNewtypesSpec() extends munit.FunSuite {
5454
)
5555
}
5656

57+
test("should allow to derive typeclasses in a generic way") {
58+
trait MyCodec[A] {
59+
def decode(str: String): Either[String, A]
60+
def encode(a: A): String
61+
}
62+
63+
object MyCodec {
64+
implicit val stringCodec: MyCodec[String] = new MyCodec[String] {
65+
def decode(str: String): Either[String, String] = Right(str)
66+
def encode(a: String): String = a
67+
}
68+
}
69+
70+
def genericCodec[A, B: MyCodec](s: Surjection[B, A]) = new MyCodec[A] {
71+
def decode(str: String): Either[String, A] =
72+
implicitly[MyCodec[B]].decode(str).flatMap(s.to)
73+
def encode(a: A): String = implicitly[MyCodec[B]].encode(s.from(a))
74+
}
75+
76+
val accountIdCodec =
77+
genericCodec[AccountId, String](implicitly[Surjection[String, AccountId]])
78+
79+
expect.same(accountIdCodec.encode(AccountId.unsafeApply(id1)), id1)
80+
expect.same(accountIdCodec.decode(id1), Right(AccountId.unsafeApply(id1)))
81+
}
82+
5783
type DeviceId = DeviceId.Type
5884
object DeviceId extends ValidatedNewtype[String] {
5985

modules/core/src-2/ValidatedNewtype.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ abstract class ValidatedNewtype[A] extends AbstractNewtype[A] { self =>
2929
@inline final def value: A = ValidatedNewtype.this.value(self)
3030
}
3131

32+
implicit val asSurjection: Surjection[A, Type] =
33+
new ValidatedNewtype.Make[A, Type] {
34+
def to(a: A): Either[String, Type] = self.apply(a)
35+
def from(t: Type): A = value(t)
36+
}
37+
3238
def unapply(t: Type): Some[A] = Some(t.value)
3339

3440
object hint {
@@ -37,5 +43,5 @@ abstract class ValidatedNewtype[A] extends AbstractNewtype[A] { self =>
3743
}
3844

3945
object ValidatedNewtype {
40-
private[smithy4s] trait Make[A, B] extends Bijection[A, B]
46+
private[smithy4s] trait Make[A, B] extends Surjection[A, B]
4147
}

modules/core/src-3/ValidatedNewtype.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ abstract class ValidatedNewtype[A] extends AbstractNewtype[A] { self =>
3030

3131
extension (orig: Type) def value: A = orig
3232

33+
implicit val asSurjection: Surjection[A, Type] =
34+
new ValidatedNewtype.Make[A, Type] {
35+
def to(a: A): Either[String, Type] = self.apply(a)
36+
def from(t: Type): A = value(t)
37+
}
38+
3339
def unapply(orig: Type): Some[A] = Some(orig.value)
3440

3541
object hint {
@@ -38,5 +44,5 @@ abstract class ValidatedNewtype[A] extends AbstractNewtype[A] { self =>
3844
}
3945

4046
object ValidatedNewtype {
41-
private[smithy4s] trait Make[A, B] extends Bijection[A, B]
47+
private[smithy4s] trait Make[A, B] extends Surjection[A, B]
4248
}

0 commit comments

Comments
 (0)