<commit_before>package org.http4s

import java.io.{File, FileOutputStream, StringReader}
import javax.xml.parsers.SAXParser

import org.http4s.EntityDecoder.DecodingException
import org.http4s.util.ReplyException
import org.xml.sax.{SAXException, SAXParseException, InputSource}
import scodec.bits.ByteVector

import scala.util.control.{NoStackTrace, NonFatal}
import scala.xml.{Elem, XML}
import scalaz.{EitherT, \/}
import scalaz.concurrent.Task
import scalaz.stream.{io, process1}
import scalaz.syntax.monad._

import util.UrlFormCodec.{ decode => formDecode }
import util.ByteVectorInstances.byteVectorMonoidInstance


/** A type that can be used to decode an [[EntityBody]]
  * EntityDecoder is used to attempt to decode an [[EntityBody]] returning the
  * entire resulting T. If an error occurs it will result in a failed Task
  * These are not streaming constructs.
  * @tparam T result type produced by the decoder
  */
sealed trait EntityDecoder[T] { self =>

  final def apply(msg: Message): Task[T] = decode(msg).valueOr(throw _)

  def decode(msg: Message): DecodeResult[T]

  def consumes: Set[MediaRange]

  def map[T2](f: T => T2): EntityDecoder[T2] = new EntityDecoder[T2] {
    override def consumes: Set[MediaRange] = self.consumes

    override def decode(msg: Message): DecodeResult[T2] = self.decode(msg).map(f)
  }

//  def orElse[T2 >: T](other: EntityDecoder[T2]): EntityDecoder[T2] = new EntityDecoder.OrDec(this, other)

  def matchesMediaType(msg: Message): Boolean = {
    if (consumes.nonEmpty) {
      msg.headers.get(Header.`Content-Type`) match {
        case Some(h) => matchesMediaType(h.mediaType)
        case None    => false
      }
    }
    else false
  }

  def matchesMediaType(mediaType: MediaType): Boolean = consumes.nonEmpty && {
    consumes.exists(_.satisfiedBy(mediaType))
  }
}

/** EntityDecoder is used to attempt to decode an [[EntityBody]]
  * This companion object provides a way to create `new EntityDecoder`s along
  * with some commonly used instances which can be resolved implicitly.
  */
object EntityDecoder extends EntityDecoderInstances {
  case class DecodingException(reason: String, cause: Option[Throwable] = None)
    extends Exception(reason, cause.orNull)
    with ReplyException
    with NoStackTrace
  {<commit_msg>Bring back EntityDecoder.orElse.<commit_after>package org.http4s

import java.io.{File, FileOutputStream, StringReader}
import javax.xml.parsers.SAXParser

import org.http4s.EntityDecoder.DecodingException
import org.http4s.util.ReplyException
import org.xml.sax.{SAXException, SAXParseException, InputSource}
import scodec.bits.ByteVector

import scala.annotation.unchecked.uncheckedVariance
import scala.util.control.{NoStackTrace, NonFatal}
import scala.xml.{Elem, XML}
import scalaz.Liskov.{<~<, refl}
import scalaz.{IList, EitherT, \/}
import scalaz.concurrent.Task
import scalaz.stream.{io, process1}
import scalaz.syntax.monad._

import util.UrlFormCodec.{ decode => formDecode }
import util.ByteVectorInstances.byteVectorMonoidInstance


/** A type that can be used to decode an [[EntityBody]]
  * EntityDecoder is used to attempt to decode an [[EntityBody]] returning the
  * entire resulting T. If an error occurs it will result in a failed Task
  * These are not streaming constructs.
  * @tparam T result type produced by the decoder
  */
sealed trait EntityDecoder[T] { self =>

  final def apply(msg: Message): Task[T] = decode(msg).valueOr(throw _)

  def decode(msg: Message): DecodeResult[T]

  def consumes: Set[MediaRange]

  def map[T2](f: T => T2): EntityDecoder[T2] = new EntityDecoder[T2] {
    override def consumes: Set[MediaRange] = self.consumes

    override def decode(msg: Message): DecodeResult[T2] = self.decode(msg).map(f)
  }

  def orElse[T2](other: EntityDecoder[T2])(implicit ev: T <~< T2): EntityDecoder[T2] =
    new EntityDecoder.OrDec(widen[T2], other)

  def matchesMediaType(msg: Message): Boolean = {
    if (consumes.nonEmpty) {
      msg.headers.get(Header.`Content-Type`) match {
        case Some(h) => matchesMediaType(h.mediaType)
        case None    => false
      }
    }
    else false
  }

  def matchesMediaType(mediaType: MediaType): Boolean = consumes.nonEmpty && {
    consumes.exists(_.satisfiedBy(mediaType))
  }

  // shamelessly stolen from IList
  def widen[B](implicit ev: T <~< B): EntityDecoder[B] =
    ev.subst[({type λ[-α] = EntityDecoder[α @uncheckedVariance] <~< EntityDecoder[B]})#λ](refl)(this)
}

/** EntityDecoder is used to attempt to decode an [[EntityBody]]
  * This companion object provides a way to create `new EntityDecoder`s along
  * with some commonly used instances which can be resolved implicitly.
  */
object EntityDecoder extends EntityDecoderInstances {
  case class DecodingException(reason: String, cause: Option[Throwable] = None)
    extends Exception(reason, cause.orNull)
    with ReplyException
    with NoStackTrace
  {
{'fraction_non_alphanumeric': 0.10800896678214796, 'fraction_numerical': 0.005298553087426126, 'mean_word_length': 4.459399332591769, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7481092', 'n_tokens_mistral': 1547, 'n_tokens_neox': 1510, 'n_words': 425}