total-map
total-map is a small library for working with types which have finite set of possible values.
Why?
To have a Map[K, V]
that guarantees totality of apply
.
What?
The core of the library is just two things:
A typeclass which express all possible values of given type
trait AllValues[T] {
def toSet: Set[T]
}
And a data structure which guarantees that there exist an entry for every possible key
trait TotalMap[K, +V] {
def toMap: Map[K, V]
def apply(k: K): V
}
How?
Install
libraryDependencies += "com.github.krever" % "total-map" % "0.0.3+1-ee160804"
Import
import totalmap._
An then you need to have an instance of AllValues[T]
. It can be acquired in few ways:
Create named set
val myStrings = NamedSet("a", "b", "c")
// myStrings: NamedSet[String] = totalmap.NamedSet$$anon$2@7f1f8381
import myStrings.allValues
implicitly[AllValues[myStrings.Elem]]
// res1: AllValues[myStrings.Elem] = AllValues(a,b,c)
Use preexisting instances
implicitly[AllValues[Unit]]
// res2: AllValues[Unit] = AllValues(())
implicitly[AllValues[Boolean]]
// res3: AllValues[Boolean] = AllValues(true,false)
Instances that require materializing big collections are not available, but might come if someone comes with reasonable use case
implicitly[AllValues[Int]]
// error: could not find implicit value for parameter e: totalmap.AllValues[Int]
// implicitly[AllValues[Int]]
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
Enumeratum
You can get enumeratum
support by installing
libraryDependencies += "com.github.krever" % "total-map-enumeratum" % "0.0.3+1-ee160804"
So when you have an Enum
import enumeratum._
sealed trait Animal extends EnumEntry
object Animal extends Enum[Animal] {
case object Cat extends Animal
case object Dog extends Animal
override def values: scala.collection.immutable.IndexedSeq[Animal] = findValues
}
You can the instances for free
import totalmap.modules.enumeratum._
implicitly[AllValues[Animal]]
// res5: AllValues[Animal] = AllValues(Cat,Dog)
Pureconfig support
You can load TotalMap
s directly from config. This works currently only for String
s as keys.
import totalmap._
import com.typesafe.config.ConfigFactory
import pureconfig._
import totalmap.modules.pureconfig._
val mySet = NamedSet("a", "b", "c")
// mySet: NamedSet[String] = totalmap.NamedSet$$anon$2@7881b440
import mySet.allValues
implicitly[AllValues[mySet.Elem]]
// res7: AllValues[mySet.Elem] = AllValues(a,b,c)
val cfg = ConfigFactory.parseString(
"""
|a = foo
|b = bar
|c = baz
""".stripMargin
)
// cfg: com.typesafe.config.Config = Config(SimpleConfigObject({"a":"foo","b":"bar","c":"baz"}))
val result = pureconfig.loadConfig[TotalMap[mySet.Elem, String]](cfg)
// result: ConfigReader.Result[TotalMap[mySet.Elem, String]] = Right(
// TotalMap(b -> bar,a -> foo,c -> baz)
// )