@@ -8,7 +8,7 @@ import scala.annotation.implicitNotFound
88
99import scala .util .control
1010
11- import scala .collection .Seq
11+ import scala .collection .{ generic , Seq }
1212import scala .collection .compat ._
1313import scala .collection .immutable .Map
1414import scala .collection .mutable .Builder
@@ -144,14 +144,16 @@ object Reads extends ConstraintReads with PathReads with DefaultReads with Gener
144144
145145 def map [A , B ](m : Reads [A ], f : A => B ): Reads [B ] = m.map(f)
146146
147- def apply [A , B ](mf : Reads [A => B ], ma : Reads [A ]): Reads [B ] = new Reads [B ] { def reads (js : JsValue ) = applicativeJsResult(mf.reads(js), ma.reads(js)) }
148-
147+ def apply [A , B ](mf : Reads [A => B ], ma : Reads [A ]): Reads [B ] = new Reads [B ] {
148+ def reads (js : JsValue ): JsResult [B ] =
149+ applicativeJsResult(mf.reads(js), ma.reads(js))
150+ }
149151 }
150152
151153 implicit def alternative (implicit a : Applicative [Reads ]): Alternative [Reads ] = new Alternative [Reads ] {
152154 val app = a
153155 def | [A , B >: A ](alt1 : Reads [A ], alt2 : Reads [B ]): Reads [B ] = new Reads [B ] {
154- def reads (js : JsValue ) = alt1.reads(js) match {
156+ def reads (js : JsValue ): JsResult [ B ] = alt1.reads(js) match {
155157 case r @ JsSuccess (_, _) => r
156158 case JsError (es1) => alt2.reads(js) match {
157159 case r2 @ JsSuccess (_, _) => r2
@@ -160,13 +162,14 @@ object Reads extends ConstraintReads with PathReads with DefaultReads with Gener
160162 }
161163 }
162164
163- def empty : Reads [Nothing ] =
164- new Reads [Nothing ] { def reads (js : JsValue ) = JsError (Seq ()) }
165-
165+ def empty : Reads [Nothing ] = NothingReads
166166 }
167167
168+ /**
169+ * Returns an instance which uses `f` as [[Reads.reads ]] function.
170+ */
168171 def apply [A ](f : JsValue => JsResult [A ]): Reads [A ] =
169- new Reads [A ] { def reads (json : JsValue ) = f(json ) }
172+ new Reads [A ] { def reads (js : JsValue ) = f(js ) }
170173
171174 implicit def functorReads (implicit a : Applicative [Reads ]) = new Functor [Reads ] {
172175 def fmap [A , B ](reads : Reads [A ], f : A => B ): Reads [B ] = a.map(reads, f)
@@ -187,44 +190,6 @@ object Reads extends ConstraintReads with PathReads with DefaultReads with Gener
187190 implicit val JsArrayReducer = Reducer [JsValue , JsArray ](js => JsArray (Array (js)))
188191}
189192
190- /**
191- * Low priority reads.
192- *
193- * This exists as a compiler performance optimization, so that the compiler doesn't have to rule them out when
194- * DefaultReads provides a simple match.
195- *
196- * See https://github.com/playframework/playframework/issues/4313 for more details.
197- */
198- trait LowPriorityDefaultReads extends EnvReads {
199-
200- /**
201- * Generic deserializer for collections types.
202- */
203- implicit def traversableReads [F [_], A ](implicit bf : Factory [A , F [A ]], ra : Reads [A ]) = new Reads [F [A ]] {
204- def reads (json : JsValue ) = json match {
205- case JsArray (ts) =>
206-
207- type Errors = Seq [(JsPath , Seq [JsonValidationError ])]
208- def locate (e : Errors , idx : Int ) = e.map { case (p, valerr) => (JsPath (idx)) ++ p -> valerr }
209-
210- ts.iterator.zipWithIndex.foldLeft(Right (Vector .empty): Either [Errors , Vector [A ]]) {
211- case (acc, (elt, idx)) => (acc, ra.reads(elt)) match {
212- case (Right (vs), JsSuccess (v, _)) => Right (vs :+ v)
213- case (Right (_), JsError (e)) => Left (locate(e, idx))
214- case (Left (e), _ : JsSuccess [_]) => Left (e)
215- case (Left (e1), JsError (e2)) => Left (e1 ++ locate(e2, idx))
216- }
217- }.fold(JsError .apply, { res =>
218- val builder = bf.newBuilder
219- builder.sizeHint(res)
220- builder ++= res
221- JsSuccess (builder.result())
222- })
223- case _ => JsError (Seq (JsPath -> Seq (JsonValidationError (" error.expected.jsarray" ))))
224- }
225- }
226- }
227-
228193/**
229194 * Default deserializer type classes.
230195 */
@@ -382,16 +347,17 @@ trait DefaultReads extends LowPriorityDefaultReads {
382347 *
383348 * @param enum a `scala.Enumeration`.
384349 */
385- def enumNameReads [E <: Enumeration ](enum : E ): Reads [E # Value ] = new Reads [E # Value ] {
386- def reads (json : JsValue ) = json match {
387- case JsString (str) =>
388- enum .values
389- .find(_.toString == str)
390- .map(JsSuccess (_))
391- .getOrElse(JsError (Seq (JsPath -> Seq (JsonValidationError (" error.expected.validenumvalue" )))))
392- case _ => JsError (Seq (JsPath -> Seq (JsonValidationError (" error.expected.enumstring" ))))
350+ def enumNameReads [E <: Enumeration ](enum : E ): Reads [E # Value ] =
351+ new Reads [E # Value ] {
352+ def reads (json : JsValue ): JsResult [E # Value ] = json match {
353+ case JsString (str) =>
354+ enum .values
355+ .find(_.toString == str)
356+ .map(JsSuccess (_))
357+ .getOrElse(JsError (Seq (JsPath -> Seq (JsonValidationError (" error.expected.validenumvalue" )))))
358+ case _ => JsError (Seq (JsPath -> Seq (JsonValidationError (" error.expected.enumstring" ))))
359+ }
393360 }
394- }
395361
396362 /**
397363 * Deserializer for Boolean types.
@@ -535,9 +501,11 @@ trait DefaultReads extends LowPriorityDefaultReads {
535501 /**
536502 * Deserializer for Array[T] types.
537503 */
538- implicit def ArrayReads [T : Reads : ClassTag ]: Reads [Array [T ]] = new Reads [Array [T ]] {
539- def reads (json : JsValue ) = json.validate[List [T ]].map(_.toArray)
540- }
504+ implicit def ArrayReads [T : Reads : ClassTag ]: Reads [Array [T ]] =
505+ new Reads [Array [T ]] {
506+ def reads (js : JsValue ): JsResult [Array [T ]] =
507+ js.validate[List [T ]].map(_.toArray)
508+ }
541509
542510 /**
543511 * Deserializer for java.util.UUID
@@ -567,4 +535,54 @@ trait DefaultReads extends LowPriorityDefaultReads {
567535 }
568536
569537 implicit val uuidReads : Reads [java.util.UUID ] = new UUIDReader (false )
538+
539+ private [json] object NothingReads extends Reads [Nothing ] {
540+ def reads (js : JsValue ) = JsError (Seq .empty)
541+ }
542+ }
543+
544+ /**
545+ * Low priority reads.
546+ *
547+ * This exists as a compiler performance optimization, so that the compiler doesn't have to rule them out when
548+ * DefaultReads provides a simple match.
549+ *
550+ * See https://github.com/playframework/playframework/issues/4313 for more details.
551+ */
552+ trait LowPriorityDefaultReads extends EnvReads {
553+
554+ /**
555+ * Generic deserializer for collections types.
556+ */
557+ implicit def traversableReads [F [_], A ](implicit bf : generic.CanBuildFrom [F [_], A , F [A ]], ra : Reads [A ]): Reads [F [A ]] = new Reads [F [A ]] {
558+ def reads (json : JsValue ): JsResult [F [A ]] = json match {
559+ case JsArray (ts) => {
560+ type Errors = Seq [(JsPath , Seq [JsonValidationError ])]
561+ def locate (e : Errors , idx : Int ) = e.map { case (p, valerr) => (JsPath (idx)) ++ p -> valerr }
562+
563+ ts.iterator.zipWithIndex.foldLeft(Right (Vector .empty): Either [Errors , Vector [A ]]) {
564+ case (acc, (elt, idx)) => (acc, ra.reads(elt)) match {
565+ case (Right (vs), JsSuccess (v, _)) => Right (vs :+ v)
566+ case (Right (_), JsError (e)) => Left (locate(e, idx))
567+ case (Left (e), _ : JsSuccess [_]) => Left (e)
568+ case (Left (e1), JsError (e2)) => Left (e1 ++ locate(e2, idx))
569+ }
570+ }.fold(JsError .apply, { res =>
571+ val builder = bf()
572+ builder.sizeHint(res)
573+ builder ++= res
574+ JsSuccess (builder.result())
575+ })
576+ }
577+
578+ case _ => JsError (Seq (JsPath -> Seq (JsonValidationError (" error.expected.jsarray" ))))
579+ }
580+ }
581+
582+ // ---
583+
584+ protected [json] final class FunctionalReads [A ](
585+ r : JsValue => JsResult [A ]) extends Reads [A ] {
586+ def reads (v : JsValue ): JsResult [A ] = r(v)
587+ }
570588}
0 commit comments