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

typequux.TupleConverter.scala Maven / Gradle / Ivy

/**
  * Copyright 2019 Harshad Deo
  *
  * 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 typequux

import language.experimental.macros
import reflect.macros.whitebox.Context
import Typequux.{:+:, HNil}

/** Conversion from Tuple to [[HList]]
  *
  * @tparam T Type of the tuple
  * @tparam HL Type of the resultant HList
  *
  * @author Harshad Deo
  * @since 0.1
  */
trait Tuple2HListConverter[T, HL] {
  def apply(t: T): HL
}

/** Provides implicit definitions to convert Tuple2-22 to [[HList]]
  *
  * @author Harshad Deo
  * @since 0.1
  */
object Tuple2HListConverter {

  /** Generates [[Tuple2HListConverter]] by delegating to the macro
    *
    * @author Harshad Deo
    * @since 0.6.5
    */
  implicit def build[T, HL]: Tuple2HListConverter[T, HL] = macro buildImpl[T, HL]

  @SuppressWarnings(Array("org.wartremover.warts.Equals"))
  def buildImpl[T, HL](c: Context)(implicit wtt: c.WeakTypeTag[T]): c.Tree = {
    import c.universe._

    val wtp = wtt.tpe match {
      case z: TypeRef => z.dealias
      case z          => z
    }

    val allTupleNames = (2 to 22).map(z => s"scala.Tuple$z")
    val isTuple = allTupleNames.exists(z => wtp.typeSymbol.fullName == z)
    if (isTuple) {
      val targs = wtp.typeArgs
      val typeCollapsed = targs.foldRight[c.Tree](tq"typequux.Typequux.HNil") {
        case (v, acc) => tq"typequux.Typequux.:+:[$v, $acc]"
      }
      val tupleArgs = List(
        q"t._1",
        q"t._2",
        q"t._3",
        q"t._4",
        q"t._5",
        q"t._6",
        q"t._7",
        q"t._8",
        q"t._9",
        q"t._10",
        q"t._11",
        q"t._12",
        q"t._13",
        q"t._14",
        q"t._15",
        q"t._16",
        q"t._17",
        q"t._18",
        q"t._19",
        q"t._20",
        q"t._21",
        q"t._22"
      ).take(targs.length)

      val valueCollapsed = tupleArgs.foldRight[c.Tree](q"typequux.Typequux.HNil") {
        case (v, acc) => q"typequux.Typequux.:+:($v, $acc)"
      }
      q"""new typequux.Tuple2HListConverter[$wtp, $typeCollapsed]{
        override def apply(t: $wtp): $typeCollapsed = $valueCollapsed
        }"""
    } else {
      c.abort(c.enclosingPosition, s"Supplied type $wtp, is not a tuple")
    }
  }

}

/** Conversions from [[HList]] to Tuple
  *
  * @tparam T Type of the resultant Tuple
  * @tparam HL Type of the input HList
  *
  * @author Harshad Deo
  * @since 0.1
  */
sealed trait HList2TupleConverter[T, HL] {
  def apply(hl: HL): T
}

/** Provided implicit definition to convert [[HList]] to Tuple1.
  * Kept in a trait that is subtyped to avoid ambiguity with more specific converters
  *
  * @author Harshad Deo
  * @since 0.1
  */
trait LowPriorityHList2TupleConverter {

  /** Arity 1 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple1Converter[A]: HList2TupleConverter[(A), A :+: HNil] =
    new HList2TupleConverter[(A), A :+: HNil] {
      override def apply(hl: A :+: HNil) = hl match {
        case a :+: HNil => (a)
      }
    }
}

/** Provides implicit definitions to convert Tuple2-18 to [[HList]]. Beyond Tuple18, the implicit search takes too long
  * to be practical
  *
  * @author Harshad Deo
  * @since 0.1
  */
object HList2TupleConverter extends LowPriorityHList2TupleConverter {

  /** Arity 2 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple2Converter[A, B]: HList2TupleConverter[(A, B), A :+: B :+: HNil] =
    new HList2TupleConverter[(A, B), A :+: B :+: HNil] {
      override def apply(hl: A :+: B :+: HNil) = hl match {
        case a :+: b :+: HNil => (a, b)
      }
    }

  /** Arity 3 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple3Converter[A, B, C]: HList2TupleConverter[(A, B, C), A :+: B :+: C :+: HNil] =
    new HList2TupleConverter[(A, B, C), A :+: B :+: C :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: HNil) = hl match {
        case a :+: b :+: c :+: HNil => (a, b, c)
      }
    }

  /** Arity 4 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple4Converter[A, B, C, D]: HList2TupleConverter[(A, B, C, D), A :+: B :+: C :+: D :+: HNil] =
    new HList2TupleConverter[(A, B, C, D), A :+: B :+: C :+: D :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: HNil => (a, b, c, d)
      }
    }

  /** Arity 5 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple5Converter[A, B, C, D, E]
    : HList2TupleConverter[(A, B, C, D, E), A :+: B :+: C :+: D :+: E :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E), A :+: B :+: C :+: D :+: E :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: HNil => (a, b, c, d, e)
      }
    }

  /** Arity 6 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple6Converter[A, B, C, D, E, F]
    : HList2TupleConverter[(A, B, C, D, E, F), A :+: B :+: C :+: D :+: E :+: F :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E, F), A :+: B :+: C :+: D :+: E :+: F :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: F :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: f :+: HNil => (a, b, c, d, e, f)
      }
    }

  /** Arity 7 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple7Converter[A, B, C, D, E, F, G]
    : HList2TupleConverter[(A, B, C, D, E, F, G), A :+: B :+: C :+: D :+: E :+: F :+: G :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E, F, G), A :+: B :+: C :+: D :+: E :+: F :+: G :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: F :+: G :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: f :+: g :+: HNil => (a, b, c, d, e, f, g)
      }
    }

  /** Arity 8 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple8Converter[A, B, C, D, E, F, G, H]
    : HList2TupleConverter[(A, B, C, D, E, F, G, H), A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E, F, G, H), A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: f :+: g :+: h :+: HNil => (a, b, c, d, e, f, g, h)
      }
    }

  /** Arity 9 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple9Converter[A, B, C, D, E, F, G, H, I]
    : HList2TupleConverter[(A, B, C, D, E, F, G, H, I), A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E, F, G, H, I), A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: f :+: g :+: h :+: i :+: HNil => (a, b, c, d, e, f, g, h, i)
      }
    }

  /** Arity 10 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple10Converter[A, B, C, D, E, F, G, H, I, J]
    : HList2TupleConverter[(A, B, C, D, E, F, G, H, I, J),
                           A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E, F, G, H, I, J),
                             A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: f :+: g :+: h :+: i :+: j :+: HNil => (a, b, c, d, e, f, g, h, i, j)
      }
    }

  /** Arity 11 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple11Converter[A, B, C, D, E, F, G, H, I, J, K]
    : HList2TupleConverter[(A, B, C, D, E, F, G, H, I, J, K),
                           A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: K :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E, F, G, H, I, J, K),
                             A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: K :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: K :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: f :+: g :+: h :+: i :+: j :+: k :+: HNil =>
          (a, b, c, d, e, f, g, h, i, j, k)
      }
    }

  /** Arity 12 Converter
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def invTuple12Converter[A, B, C, D, E, F, G, H, I, J, K, L]
    : HList2TupleConverter[(A, B, C, D, E, F, G, H, I, J, K, L),
                           A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: K :+: L :+: HNil] =
    new HList2TupleConverter[(A, B, C, D, E, F, G, H, I, J, K, L),
                             A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: K :+: L :+: HNil] {
      override def apply(hl: A :+: B :+: C :+: D :+: E :+: F :+: G :+: H :+: I :+: J :+: K :+: L :+: HNil) = hl match {
        case a :+: b :+: c :+: d :+: e :+: f :+: g :+: h :+: i :+: j :+: k :+: l :+: HNil =>
          (a, b, c, d, e, f, g, h, i, j, k, l)
      }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy