Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d6a4f56

Browse files
committed
Merge pull request milessabin#524 from clhodapp/feature/unwrapped
Add Unwrapped typeclass for unwrapping in codecs
2 parents c4ac2d2 + 4782e32 commit d6a4f56

File tree

4 files changed

+406
-0
lines changed

4 files changed

+406
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2016 Miles Sabin
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package shapeless
18+
package syntax
19+
20+
object unwrapped {
21+
implicit class UnwrappedSyntax[T](val t: T) extends AnyVal {
22+
def unwrap[U](implicit uw: Unwrapped.Aux[T, U]): U = uw.unwrap(t)
23+
def wrap[W](implicit uw: Unwrapped.Aux[W, T]): W = uw.wrap(t)
24+
}
25+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2016 Miles Sabin
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package shapeless
18+
19+
import newtype._
20+
21+
trait Unwrapped[W] extends Serializable {
22+
type U
23+
def unwrap(w: W): U
24+
def wrap(u: U): W
25+
}
26+
27+
object Unwrapped extends UnwrappedInstances {
28+
type Aux[W, U0] = Unwrapped[W] { type U = U0 }
29+
def apply[W](implicit w: Unwrapped[W]): Aux[W, w.U] = w
30+
}
31+
32+
trait UnwrappedInstances extends LowPriorityUnwrappedInstances {
33+
implicit def unwrapAnyVal[W <: AnyVal, Repr, UI, UF](implicit
34+
gen: Generic.Aux[W, Repr],
35+
avh: AnyValHelper.Aux[Repr, UI],
36+
chain: Strict[Unwrapped.Aux[UI, UF]]
37+
) = new Unwrapped[W] {
38+
type U = UF
39+
def unwrap(w: W): U = chain.value.unwrap(avh.unwrap(gen.to(w)))
40+
def wrap(u: U): W = gen.from(avh.wrap(chain.value.wrap(u)))
41+
}
42+
43+
sealed trait AnyValHelper[Repr] extends Serializable {
44+
type U
45+
def unwrap(r: Repr): U
46+
def wrap(u: U): Repr
47+
}
48+
object AnyValHelper {
49+
type Aux[Repr, U0] = AnyValHelper[Repr] { type U = U0 }
50+
implicit def sizeOneHListHelper[T] =
51+
SizeOneHListHelper.asInstanceOf[AnyValHelper.Aux[T :: HNil, T]]
52+
val SizeOneHListHelper = new AnyValHelper[Any :: HNil] {
53+
type U = Any
54+
def unwrap(hl: Any :: HNil): Any = hl.head
55+
def wrap(t: Any): Any :: HNil = t :: HNil
56+
}
57+
}
58+
59+
implicit def newtypeUnwrapped[UI, Ops, UF](implicit
60+
chain: Strict[Unwrapped.Aux[UI, UF]]
61+
) = chain.value.asInstanceOf[Unwrapped.Aux[Newtype[UI, Ops], UF]]
62+
63+
}
64+
65+
trait LowPriorityUnwrappedInstances {
66+
val theSelfUnwrapped =
67+
new Unwrapped[Any] {
68+
type U = Any
69+
def unwrap(t: Any) = t
70+
def wrap(t: Any) = t
71+
}
72+
implicit def selfUnwrapped[T] =
73+
theSelfUnwrapped.asInstanceOf[Unwrapped.Aux[T, T]]
74+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
2+
/*
3+
* Copyright (c) 2016 Miles Sabin
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package shapeless
19+
20+
import org.junit.Test
21+
22+
object WrappedTests {
23+
trait TestTag
24+
case class AvWrapper(stringValue: String) extends AnyVal
25+
}
26+
import WrappedTests._
27+
28+
class UnwrappedTests {
29+
30+
sealed trait Pass[T] {
31+
type U
32+
def actual(t: T): T
33+
def unwrapped(t: T): U
34+
def wrapped(u: U): T
35+
}
36+
object Pass {
37+
type Aux[T, U0] = Pass[T] { type U = U0 }
38+
implicit def unwrappedPasses[W, U0](implicit uw: Unwrapped.Aux[W, U0]): Pass.Aux[W, U0] =
39+
new Pass[W] {
40+
type U = U0
41+
def actual(w: W): W = w
42+
def unwrapped(w: W): U = uw.unwrap(w)
43+
def wrapped(u: U): W = uw.wrap(u)
44+
}
45+
}
46+
47+
@Test
48+
def testAnyVal: Unit = {
49+
val pass = the[Pass[AvWrapper]]
50+
the[pass.U =:= String]
51+
val avw = AvWrapper("testing")
52+
val actual = pass.actual(avw)
53+
val wrapped = pass.wrapped(avw.stringValue)
54+
val unwrapped = pass.unwrapped(avw)
55+
assert((actual: AvWrapper) == avw)
56+
assert((wrapped: AvWrapper) == avw)
57+
assert((unwrapped: String) == avw.stringValue)
58+
}
59+
60+
@Test
61+
def testNewtype: Unit = {
62+
import newtype._
63+
case class MyStringOps(s: String) {
64+
def stringValue: String = s
65+
}
66+
type MyString = Newtype[String, MyStringOps]
67+
def MyString(s : String) : MyString = newtype(s)
68+
implicit val mkOps = MyStringOps
69+
70+
val pass = the[Pass[MyString]]
71+
the[pass.U =:= String]
72+
val ms = MyString("testing")
73+
val actual = pass.actual(ms)
74+
val wrapped = pass.wrapped(ms.stringValue)
75+
val unwrapped = pass.unwrapped(ms)
76+
assert((actual: MyString) == ms)
77+
assert((wrapped: MyString) == ms)
78+
assert((unwrapped: String) == ms.stringValue)
79+
}
80+
81+
@Test
82+
def testScalazTagged: Unit = {
83+
84+
type Tagged[A, T] = { type Tag = T; type Self = A }
85+
type @@[T, Tag] = Tagged[T, Tag]
86+
87+
def tag[U] = new Tagger[U]
88+
class Tagger[U] {
89+
def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
90+
}
91+
def value[T](t: Tagged[T, _]): T = t.asInstanceOf[T]
92+
93+
implicit def taggedUnwrapped[UI, T, UF](implicit chain: Lazy[Unwrapped.Aux[UI, UF]]) =
94+
new Unwrapped[UI @@ T] {
95+
type U = UF
96+
def unwrap(w: UI @@ T) = chain.value.unwrap(value(w))
97+
def wrap(u: UF) = tag[T](chain.value.wrap(u))
98+
}
99+
100+
val pass = the[Pass[String @@ TestTag]]
101+
the[pass.U =:= String]
102+
val tagged = tag[TestTag]("testing")
103+
val actual = pass.actual(tagged)
104+
val wrapped = pass.wrapped(value(tagged))
105+
val unwrapped = pass.unwrapped(tagged)
106+
assert((actual: String @@ TestTag) == tagged)
107+
assert((wrapped: String @@ TestTag) == tagged)
108+
assert((unwrapped: String) == value(tagged))
109+
test.illTyped("unwrapped: String @@ TestTag")
110+
}
111+
112+
@Test
113+
def testAlreadyUnwrapped: Unit = {
114+
115+
val pass = the[Pass[String]]
116+
the[pass.U =:= String]
117+
val raw = "testing"
118+
val actual = pass.actual(raw)
119+
val wrapped = pass.wrapped(raw)
120+
val unwrapped = pass.unwrapped(raw)
121+
assert((actual: String) == raw)
122+
assert((wrapped: String) == raw)
123+
assert((unwrapped: String) == raw)
124+
}
125+
126+
@Test
127+
def unwrapsChain: Unit = {
128+
import newtype._
129+
130+
case class MyStringOps(s: AvWrapper) {
131+
def stringValue: String = s.stringValue
132+
}
133+
type MyString = Newtype[AvWrapper, MyStringOps]
134+
def MyString(a: AvWrapper): MyString = newtype(a)
135+
implicit val mkOps = MyStringOps
136+
137+
138+
val ms = MyString(AvWrapper("testing"))
139+
140+
val pass = the[Pass[MyString]]
141+
the[pass.U =:= String]
142+
val actual = pass.actual(ms)
143+
val wrapped = pass.wrapped(ms.stringValue)
144+
val unwrapped = pass.unwrapped(ms)
145+
assert((actual: MyString) == ms)
146+
assert((wrapped: MyString) == ms)
147+
assert((unwrapped: String) == ms.stringValue)
148+
}
149+
150+
@Test
151+
def testSyntax: Unit = {
152+
import syntax.unwrapped._
153+
val w = "testing".wrap[AvWrapper]
154+
test.typed(w: AvWrapper)
155+
val u = w.unwrap
156+
test.typed(u: String)
157+
}
158+
159+
}

0 commit comments

Comments
 (0)