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

amed-codec_3.0.2.1.source-code.NamedCodec.scala Maven / Gradle / Ivy

/*
 * Copyright 2022 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 dev.hnaderi.namedcodec

final case class TypeName[T](value: String) extends AnyVal
object TypeName extends TypeNamePlatform

trait CodecAdapter[Enc[_], Dec[_], R] {
  def encode[A: Enc](a: A): R
  def decode[A: Dec](r: R): Either[String, A]
}

final case class EncodedMessage[R](
    name: String,
    data: R
) {
  def rename(f: String => String): EncodedMessage[R] =
    copy(name = f(name))
}

trait NamedEncoder[A, R] { self =>
  def encode(a: A): EncodedMessage[R]

  final def contramap[B](f: B => A): NamedEncoder[B, R] =
    new NamedEncoder[B, R] {
      def encode(b: B): EncodedMessage[R] = self.encode(f(b))
    }
}

object NamedEncoder {
  def apply[A, R](f: A => EncodedMessage[R]): NamedEncoder[A, R] = new {
    def encode(a: A): EncodedMessage[R] = f(a)
  }
}

trait NamedDecoder[A, R] { self =>
  def decode(msg: EncodedMessage[R]): Either[String, A]
  def canDecode(msg: String): Boolean

  final def map[B](f: A => B): NamedDecoder[B, R] = new NamedDecoder[B, R] {
    def decode(msg: EncodedMessage[R]): Either[String, B] =
      self.decode(msg).map(f)
    def canDecode(msg: String): Boolean = self.canDecode(msg)
  }
}

trait NamedCodec[A, R] extends NamedEncoder[A, R], NamedDecoder[A, R] {
  self =>
  final def imap[B](fcon: B => A)(fcov: A => B): NamedCodec[B, R] =
    new NamedCodec[B, R] {
      def encode(b: B): EncodedMessage[R] = self.encode(fcon(b))
      def decode(msg: EncodedMessage[R]): Either[String, B] =
        self.decode(msg).map(fcov)
      def canDecode(msg: String): Boolean = self.canDecode(msg)
    }
  final def eimap[B](
      fcon: B => A
  )(fcov: A => Either[String, B]): NamedCodec[B, R] =
    new NamedCodec[B, R] {
      def encode(b: B): EncodedMessage[R] = self.encode(fcon(b))
      def decode(msg: EncodedMessage[R]): Either[String, B] =
        self.decode(msg).flatMap(fcov)
      def canDecode(msg: String): Boolean = self.canDecode(msg)
    }
}

object NamedCodec extends NamedCodecPlatform {
  def apply[A, R](
      enc: NamedEncoder[A, R],
      dec: NamedDecoder[A, R]
  ): NamedCodec[A, R] = new {
    export enc.*
    export dec.*
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy