All Downloads are FREE. Search and download functionalities are using the official Maven repository.

epus-client_native0.4_3.0.5.3.source-code.MessageCodec.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 Hossein Naderi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package lepus.client

import lepus.protocol.domains.*
import scodec.bits.ByteVector

import java.nio.charset.StandardCharsets
import scala.annotation.implicitNotFound

@implicitNotFound("Cannot find a way to encode ${B} into a message")
trait MessageEncoder[B] { self =>
  def encode(msg: Message[B]): MessageRaw
  final def encode(payload: B): MessageRaw = encode(Message(payload))
  final def encode(env: Envelope[B]): EnvelopeRaw =
    env.copy(message = encode(env.message))

  final def contramap[A](f: A => B): MessageEncoder[A] = new {
    override def encode(msg: Message[A]): MessageRaw =
      self.encode(msg.copy(payload = f(msg.payload)))
  }

  final def postEncode(f: MessageRaw => MessageRaw): MessageEncoder[B] = new {
    override def encode(msg: Message[B]): MessageRaw =
      f(self.encode(msg))
  }
}
object MessageEncoder {
  inline def apply[T](using enc: MessageEncoder[T]): MessageEncoder[T] = enc
  given MessageEncoder[String] = new {
    override def encode(msg: Message[String]): MessageRaw =
      msg
        .copy(payload =
          ByteVector.view(msg.payload.getBytes(StandardCharsets.UTF_8))
        )
        .withContentType(ShortString("text/plain"))
  }
  given MessageEncoder[Array[Byte]] = new {
    override def encode(msg: Message[Array[Byte]]): MessageRaw =
      msg.copy(payload = ByteVector(msg.payload))
  }
  def by[T](f: Message[T] => MessageRaw): MessageEncoder[T] = new {
    override def encode(msg: Message[T]): MessageRaw = f(msg)
  }
  def fromPayloadEncoder[T](f: T => ByteVector): MessageEncoder[T] = new {
    override def encode(msg: Message[T]): MessageRaw =
      msg.copy(payload = f(msg.payload))
  }
}

@implicitNotFound("Cannot find a way to decode a message into ${A}")
trait MessageDecoder[A] { self =>
  def decode(env: MessageRaw): Either[Throwable, Message[A]]
  final def decode(env: EnvelopeRaw): Either[Throwable, Envelope[A]] =
    decode(env.message).map(m => env.copy(message = m))

  final def map[B](f: A => B): MessageDecoder[B] = new {
    override def decode(env: MessageRaw): Either[Throwable, Message[B]] =
      self.decode(env).map(m => m.copy(payload = f(m.payload)))
  }

  final def emap[B](f: A => Either[Throwable, B]): MessageDecoder[B] = new {
    override def decode(env: MessageRaw): Either[Throwable, Message[B]] =
      self
        .decode(env)
        .flatMap(msg => f(msg.payload).map(p => msg.copy(payload = p)))
  }

  final def mapMessage[B](f: Message[A] => Message[B]): MessageDecoder[B] =
    new {
      override def decode(env: MessageRaw): Either[Throwable, Message[B]] =
        self.decode(env).map(f)
    }
  final def emapMessage[B](
      f: Message[A] => Either[Throwable, Message[B]]
  ): MessageDecoder[B] = new {
    override def decode(env: MessageRaw): Either[Throwable, Message[B]] =
      self.decode(env).flatMap(f)
  }
}
object MessageDecoder {
  inline def apply[T](using dec: MessageDecoder[T]): MessageDecoder[T] = dec
  given MessageDecoder[String] = new {
    override def decode(env: MessageRaw): Either[Throwable, Message[String]] =
      env.payload.decodeUtf8.map(p => env.copy(payload = p))
  }
  given MessageDecoder[Array[Byte]] = new {
    override def decode(
        env: MessageRaw
    ): Either[Throwable, Message[Array[Byte]]] = Right(
      env.copy(payload = env.payload.toArray)
    )
  }
  def by[T](
      f: MessageRaw => Either[Throwable, Message[T]]
  ): MessageDecoder[T] = new {
    override def decode(env: MessageRaw): Either[Throwable, Message[T]] = f(env)
  }
  def fromPayloadDecoder[T](
      f: ByteVector => Either[Throwable, T]
  ): MessageDecoder[T] = new {
    override def decode(env: MessageRaw): Either[Throwable, Message[T]] =
      f(env.payload).map(t => env.copy(payload = t))
  }
}

trait MessageCodec[T] extends MessageDecoder[T], MessageEncoder[T] { self =>
  def imap[A](in: A => T, out: T => A): MessageCodec[A] = new {
    private val enc = self.contramap(in)
    private val dec = self.map(out)

    export enc.encode
    export dec.decode
  }
  def eimap[A](in: A => T, out: T => Either[Throwable, A]): MessageCodec[A] =
    new {
      private val enc = self.contramap(in)
      private val dec = self.emap(out)

      export enc.encode
      export dec.decode
    }
}

object MessageCodec {
  inline def apply[T](using codec: MessageCodec[T]): MessageCodec[T] = codec
  def of[T](using
      enc: MessageEncoder[T],
      dec: MessageDecoder[T]
  ): MessageCodec[T] = new {
    export enc.encode
    export dec.decode
  }

  inline given [T: MessageEncoder: MessageDecoder]: MessageCodec[T] = of[T]
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy