Skip to content

Commit

Permalink
Deprecated BufText
Browse files Browse the repository at this point in the history
  • Loading branch information
vkostyukov committed Feb 11, 2017
1 parent ae01cc2 commit b06d97f
Show file tree
Hide file tree
Showing 20 changed files with 109 additions and 106 deletions.
5 changes: 3 additions & 2 deletions argonaut/src/main/scala/io/finch/argonaut/Decoders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import argonaut.{CursorHistory, DecodeJson, Json}
import argonaut.JawnParser._
import com.twitter.util.{Return, Throw, Try}
import io.finch._
import io.finch.internal.{BufText, HttpContent}
import io.finch.internal.HttpContent
import java.nio.charset.StandardCharsets
import jawn.Parser
import scala.util.{Failure, Success}
Expand All @@ -21,7 +21,8 @@ trait Decoders {
val attemptJson = cs match {
case StandardCharsets.UTF_8 =>
Parser.parseFromByteBuffer[Json](b.asByteBuffer)(facade)
case _ => Parser.parseFromString[Json](BufText.extract(b, cs))(facade)
case _ =>
Parser.parseFromString[Json](b.asString(cs))(facade)
}

attemptJson match {
Expand Down
10 changes: 5 additions & 5 deletions argonaut/src/main/scala/io/finch/argonaut/Encoders.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.finch.argonaut

import argonaut.{EncodeJson, Json, PrettyParams}
import com.twitter.io.Buf
import io.finch.Encode
import io.finch.internal.BufText

trait Encoders {

Expand All @@ -12,10 +12,10 @@ trait Encoders {
* Maps Argonaut's [[EncodeJson]] to Finch's [[Encode]].
*/
implicit def encodeArgonaut[A](implicit e: EncodeJson[A]): Encode.Json[A] =
Encode.json((a, cs) => BufText(printer.pretty(e.encode(a)), cs))
Encode.json((a, cs) => Buf.ByteArray.Owned(printer.pretty(e.encode(a)).getBytes(cs.name)))

implicit def encodeExceptionArgonaut[A <: Exception]: EncodeJson[A] = new EncodeJson[A] {
override def encode(a: A): Json =
Json.obj(("message", Option(a.getMessage).fold(Json.jNull)(Json.jString)))
implicit val encodeExceptionArgonaut: EncodeJson[Exception] = new EncodeJson[Exception] {
override def encode(e: Exception): Json =
Json.obj("message" -> Option(e.getMessage).fold(Json.jNull)(Json.jString))
}
}
7 changes: 4 additions & 3 deletions benchmarks/src/main/scala/io/finch/data/Foo.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.finch.data

import com.twitter.io.Buf
import com.twitter.util.Return
import io.finch.{Decode, DecodeEntity, Encode}
import io.finch.internal.BufText
import io.finch.internal.HttpContent

case class Foo(s: String)

Expand All @@ -11,8 +12,8 @@ object Foo {
DecodeEntity.instance(s => Return(Foo(s)))

implicit def decodeFoo[CT <: String]: Decode.Aux[Foo, CT] =
Decode.instance((b, cs) => Return(Foo(BufText.extract(b, cs))))
Decode.instance((b, cs) => Return(Foo(b.asString(cs))))

implicit def encodeFoo[CT <: String]: Encode.Aux[Foo, CT] =
Encode.instance((f, cs) => BufText(f.s, cs))
Encode.instance((f, cs) => Buf.ByteArray.Owned(f.s.getBytes(cs.name)))
}
4 changes: 2 additions & 2 deletions circe/src/main/scala/io/finch/circe/Decoders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.twitter.util.{Return, Throw, Try}
import io.circe.Decoder
import io.circe.jawn._
import io.finch.Decode
import io.finch.internal.{BufText, HttpContent}
import io.finch.internal.HttpContent
import java.nio.charset.StandardCharsets

trait Decoders {
Expand All @@ -15,7 +15,7 @@ trait Decoders {
implicit def decodeCirce[A: Decoder]: Decode.Json[A] = Decode.json { (b, cs) =>
val attemptJson = cs match {
case StandardCharsets.UTF_8 => decodeByteBuffer[A](b.asByteBuffer)
case _ => decode[A](BufText.extract(b, cs))
case _ => decode[A](b.asString(cs))
}

attemptJson.fold[Try[A]](Throw.apply, Return.apply)
Expand Down
10 changes: 4 additions & 6 deletions circe/src/main/scala/io/finch/circe/Encoders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package io.finch.circe
import com.twitter.io.Buf
import io.circe.{Encoder, Json}
import io.finch.Encode
import io.finch.internal.BufText
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets

Expand All @@ -17,11 +16,10 @@ trait Encoders {
*/
implicit def encodeCirce[A](implicit e: Encoder[A]): Encode.Json[A] = Encode.json {
case (a, StandardCharsets.UTF_8) => Buf.ByteBuffer.Owned(printBytes(e(a)))
case (a, cs) => BufText(printString(e(a)), cs)
case (a, cs) => Buf.ByteArray.Owned(printString(e(a)).getBytes(cs.name))
}

implicit def encodeExceptionCirce[A <: Exception]: Encoder[A] = new Encoder[A] {
override def apply(e: A): Json =
Json.obj(("message", Option(e.getMessage).fold(Json.Null)(Json.fromString)))
}
implicit val encodeExceptionCirce: Encoder[Exception] = Encoder.instance(e =>
Json.obj("message" -> Option(e.getMessage).fold(Json.Null)(Json.fromString))
)
}
7 changes: 3 additions & 4 deletions core/src/main/scala/io/finch/Encode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.finch

import cats.Show
import com.twitter.io.Buf
import io.finch.internal.BufText
import java.nio.charset.Charset

/**
Expand Down Expand Up @@ -34,7 +33,7 @@ trait LowPriorityEncodeInstances {
instance[A, Text.Plain](fn)

implicit def encodeShowAsTextPlain[A](implicit s: Show[A]): Text[A] =
text((a, cs) => BufText(s.show(a), cs))
text((a, cs) => Buf.ByteArray.Owned(s.show(a).getBytes(cs.name)))
}

trait HighPriorityEncodeInstances extends LowPriorityEncodeInstances {
Expand Down Expand Up @@ -63,8 +62,8 @@ object Encode extends HighPriorityEncodeInstances {
@inline final def apply[A, CT <: String](implicit e: Aux[A, CT]): Aux[A, CT] = e

implicit val encodeExceptionAsTextPlain: Text[Exception] =
text((e, cs) => BufText(Option(e.getMessage).getOrElse(""), cs))
text((e, cs) => Buf.ByteArray.Owned(Option(e.getMessage).getOrElse("").getBytes(cs.name)))

implicit val encodeStringAsTextPlain: Text[String] =
text((s, cs) => BufText(s, cs))
text((s, cs) => Buf.ByteArray.Owned(s.getBytes(cs.name)))
}
9 changes: 1 addition & 8 deletions core/src/main/scala/io/finch/Endpoints.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import cats.data.NonEmptyList
import com.twitter.concurrent.AsyncStream
import com.twitter.finagle.http.{Cookie, Method, Request}
import com.twitter.finagle.http.exp.Multipart.FileUpload
import com.twitter.finagle.netty3.ChannelBufferBuf
import com.twitter.io.Buf
import com.twitter.util.{Future, Try}
import io.catbird.util.Rerunnable
Expand Down Expand Up @@ -281,13 +280,7 @@ trait Endpoints {
private[this] def requestBodyString(req: Request): Option[String] =
req.contentLength match {
case Some(0) => someEmptyString
case Some(_) =>
val buffer = ChannelBufferBuf.Owned.extract(req.content)
val charset = req.charsetOrUtf8
// Note: We usually have an array underneath the ChannelBuffer (at least on Netty 3).
// This check is mostly about a safeguard.
if (buffer.hasArray) Some(new String(buffer.array(), 0, buffer.readableBytes(), charset))
else Some(buffer.toString(charset))
case Some(_) => Some(req.content.asString(req.charsetOrUtf8))
case None => None
}

Expand Down
15 changes: 11 additions & 4 deletions core/src/main/scala/io/finch/internal/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ package object internal {
/**
* Converts this string to the optional boolean value.
*/
def tooBoolean: Option[Boolean] = s match {
final def tooBoolean: Option[Boolean] = s match {
case "true" => someTrue
case "false" => someFalse
case _ => None
Expand All @@ -81,27 +81,28 @@ package object internal {
* Converts this string to the optional integer value. The maximum allowed length for a number
* string is 32.
*/
def tooInt: Option[Int] =
final def tooInt: Option[Int] =
if (s.length == 0 || s.length > 32) None
else parseLong(s, Int.MinValue, Int.MaxValue).map(_.toInt)

/**
* Converts this string to the optional integer value. The maximum allowed length for a number
* string is 32.
*/
def tooLong: Option[Long] =
final def tooLong: Option[Long] =
if (s.length == 0 || s.length > 32) None
else parseLong(s, Long.MinValue, Long.MaxValue)
}

// TODO: Move to twitter/util
object BufText {
@deprecated("Buf.ByteArray.Owned(string.getBytes(charset))", "0.13")
def apply(s: String, cs: Charset): Buf = {
val enc = Charsets.encoder(cs)
val cb = CharBuffer.wrap(s.toCharArray)
Buf.ByteBuffer.Owned(enc.encode(cb))
}

@deprecated("HttpContent.asString(charset)", "0.13")
def extract(buf: Buf, cs: Charset): String = {
val dec = Charsets.decoder(cs)
val bb = Buf.ByteBuffer.Owned.extract(buf).asReadOnlyBuffer
Expand Down Expand Up @@ -142,5 +143,11 @@ package object internal {

result
}

// Returns content as String (tries to avoid copying).
def asString(cs: Charset): String = {
val (array, offset, length) = asByteArrayWithOffsetAndLength
new String(array, offset, length, cs.name)
}
}
}
3 changes: 1 addition & 2 deletions core/src/test/scala/io/finch/EncodeLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import cats.instances.AllInstances
import cats.laws._
import cats.laws.discipline._
import com.twitter.io.Buf
import io.finch.internal.BufText
import org.scalacheck.{Arbitrary, Prop}
import org.typelevel.discipline.Laws

Expand All @@ -16,7 +15,7 @@ trait EncodeLaws[A, CT <: String] extends Laws with MissingInstances with AllIns
def encode: Encode.Aux[A, CT]

def roundTrip(a: A, cs: Charset): IsEq[Buf] =
encode(a, cs) <-> BufText(a.toString, cs)
encode(a, cs) <-> Buf.ByteArray.Owned(a.toString.getBytes(cs))

def all(implicit A: Arbitrary[A], CS: Arbitrary[Charset], eq: Eq[A]): RuleSet =
new DefaultRuleSet(
Expand Down
4 changes: 1 addition & 3 deletions core/src/test/scala/io/finch/EncodeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import java.nio.charset.Charset
import java.util.UUID

import com.twitter.io.Buf
import io.finch.internal.BufText

class EncodeSpec extends FinchSpec {

Expand All @@ -29,10 +28,9 @@ class EncodeSpec extends FinchSpec {
it should "encode exceptions" in {
check { (s: String, cs: Charset) =>
val e = new Exception(s)

val text = Encode[Exception, Text.Plain].apply(e, cs)

text === BufText(s, cs)
text === Buf.ByteArray.Owned(s.getBytes(cs.name))
}
}
}
4 changes: 2 additions & 2 deletions core/src/test/scala/io/finch/EndToEndSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ package io.finch

import com.twitter.finagle.Service
import com.twitter.finagle.http.{Request, Response, Status}
import com.twitter.io.Buf
import com.twitter.util.Await
import io.finch.data.Foo
import io.finch.internal.BufText

class EndToEndSpec extends FinchSpec {

behavior of "Finch"

it should "convert coproduct Endpoints into Services" in {
implicit val encodeException: Encode.Text[Exception] =
Encode.text((_, cs) => BufText("ERR!", cs))
Encode.text((_, cs) => Buf.ByteArray.Owned("ERR!".getBytes(cs.name)))

val service: Service[Request, Response] = (
get("foo" :: string) { s: String => Ok(Foo(s)) } :+:
Expand Down
13 changes: 7 additions & 6 deletions core/src/test/scala/io/finch/InputSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import java.nio.charset.Charset

import com.twitter.finagle.http.Method
import com.twitter.io.Buf
import io.finch.internal.BufText
import io.finch.data.Foo
import io.finch.internal.HttpContent

class InputSpec extends FinchSpec {

Expand Down Expand Up @@ -40,14 +41,14 @@ class InputSpec extends FinchSpec {
}

it should "add content corresponding to a class through withBody[JSON]" in {
implicit val encodeException: Encode.Json[Exception] = Encode.json(
(a, cc) => BufText(s"""{"message":"${a.getMessage}"}""", cc)
implicit val encodeFoo: Encode.Json[Foo] = Encode.json(
(a, cs) => Buf.ByteArray.Owned(a.s.getBytes(cs.name))
)

check { (i: Input, s: String, cs: Charset) =>
val input = i.withBody[Application.Json](new Exception(s), Some(cs))
check { (i: Input, f: Foo, cs: Charset) =>
val input = i.withBody[Application.Json](f, Some(cs))

input.request.content === BufText(s"""{"message":"$s"}""", cs) &&
input.request.content.asString(cs) === f.s &&
input.request.contentType === Some(s"application/json;charset=${cs.displayName.toLowerCase}")
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/scala/io/finch/data/Foo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package io.finch.data
import cats.Show
import com.twitter.util.Return
import io.finch.{Decode, DecodeEntity}
import io.finch.internal._
import io.finch.internal.HttpContent
import org.scalacheck.{Arbitrary, Gen}

case class Foo(s: String)
Expand All @@ -16,7 +16,7 @@ object Foo {
DecodeEntity.instance(s => Return(Foo(s)))

implicit val decodeTextFoo: Decode.Text[Foo] =
Decode.text((b, cs) => Return(Foo(BufText.extract(b, cs))))
Decode.text((b, cs) => Return(Foo(b.asString(cs))))

implicit val arbitraryFoo: Arbitrary[Foo] =
Arbitrary(Gen.alphaStr.map(Foo.apply))
Expand Down
14 changes: 7 additions & 7 deletions jackson/src/main/scala/io/finch/jackson/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import com.twitter.io.Buf
import com.twitter.util.Try
import io.finch.internal.{BufText, HttpContent, Utf32}
import io.finch.internal.{HttpContent, Utf32}
import java.nio.charset.StandardCharsets

package object jackson {
Expand All @@ -20,23 +20,23 @@ package object jackson {
case (a, StandardCharsets.UTF_8) =>
Buf.ByteArray.Owned(objectMapper.writeValueAsBytes(a))
case (a, cs) =>
BufText(objectMapper.writeValueAsString(a), cs)
Buf.ByteArray.Owned(objectMapper.writeValueAsString(a).getBytes(cs.name))
}

implicit def decodeJackson[A](implicit m: Manifest[A]): Decode.Json[A] = Decode.json {
case (buf, StandardCharsets.UTF_8 | StandardCharsets.UTF_16 | Utf32) =>
val (array, offset, length) = buf.asByteArrayWithOffsetAndLength
Try(objectMapper.readValue[A](array, offset, length))
case (buf, cs) =>
Try(objectMapper.readValue[A](BufText.extract(buf, cs)))
Try(objectMapper.readValue[A](buf.asString(cs)))
}

implicit def encodeJackson[A]: Encode.Json[A] = encodeJacksonInstance.asInstanceOf[Encode.Json[A]]

implicit def encodeExceptionJackson[A <: Exception]: Encode.Json[A] =
Encode.json((a, cs) => {
implicit val encodeExceptionJackson: Encode.Json[Exception] =
Encode.json { (a, cs) =>
val rootNode = objectMapper.createObjectNode()
rootNode.put("message", a.getMessage)
BufText(objectMapper.writeValueAsString(rootNode), cs)
})
Buf.ByteArray.Owned(objectMapper.writeValueAsString(rootNode).getBytes(cs.name))
}
}
Loading

0 comments on commit b06d97f

Please sign in to comment.