Last active
August 3, 2017 21:33
-
-
Save kolemannix/c8bd6f58c270a77a9b7a593a6ee182b2 to your computer and use it in GitHub Desktop.
Phantom Types, higher kinds, and F-Bounded polymorphism PoC (abstraction over en/decryption
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package lshack | |
import scala.concurrent.{ ExecutionContext, Future } | |
import scala.languageFeature.higherKinds | |
import scala.util.{ Success, Try } | |
import lshack.Values._ | |
object Values { | |
sealed trait State | |
trait Encrypted extends State | |
trait Decrypted extends State | |
trait Encryptable[V[S <: State], Dep, F[A]] { | |
def encrypt[S <: Decrypted](d: V[S], dep: Dep): F[V[Encrypted]] | |
def decrypt[S <: Encrypted](d: V[S], dep: Dep): F[V[Decrypted]] | |
} | |
implicit class EncryptOp[S <: Decrypted, V[S <: State], F[A], Dep](v: V[S])(implicit val ev: Encryptable[V, Dep, F], dep: Dep) { | |
def encrypt: F[V[Encrypted]] = ev.encrypt(v, dep) | |
} | |
implicit class DecryptOp[S <: Encrypted, V[S <: State], F[A], Dep](v: V[S])(implicit val ev: Encryptable[V, Dep, F], dep: Dep) { | |
def decrypt: F[V[Decrypted]] = ev.decrypt(v, dep) | |
} | |
type BasicEncryptable[V[S <: State]] = Encryptable[V, Unit, Box] | |
implicit class BasicEncryptOp[S <: Decrypted, V[S <: State]](v: V[S])(implicit val ev: BasicEncryptable[V]) { def encrypt: Box[V[Encrypted]] = ev.encrypt(v, ()) } | |
implicit class BasicDecryptOp[S <: Encrypted, V[S <: State]](v: V[S])(implicit val ev: BasicEncryptable[V]) { def decrypt: Box[V[Decrypted]] = ev.decrypt(v, ()) } | |
} | |
class Box[A](val a: A) | |
case class IntValue[S <: State](x: Int) | |
object IntValue { | |
implicit val encryptable: BasicEncryptable[IntValue] = new BasicEncryptable[IntValue] { | |
def encrypt[S <: Decrypted](i: IntValue[S], dep: Unit): Box[IntValue[Encrypted]] = new Box(i.copy(x = i.x + 100)) | |
def decrypt[S <: Encrypted](i: IntValue[S], dep: Unit): Box[IntValue[Decrypted]] = new Box(i.copy(x = i.x - 100)) | |
} | |
} | |
case class StringValue[S <: State](x: String) | |
object StringValue { | |
implicit val encryptable: Encryptable[StringValue, String, Try] = new Encryptable[StringValue, String, Try] { | |
def encrypt[S <: Decrypted](i: StringValue[S], dep: String): Try[StringValue[Encrypted]] = { | |
Success(i.copy(x = dep + i.x)) | |
} | |
def decrypt[S <: Encrypted](i: StringValue[S], dep: String): Try[StringValue[Decrypted]] = { | |
Success(i.copy(x = dep + i.x)) | |
} | |
} | |
} | |
trait KmsService { | |
type Key | |
def getKey(key: String): Key | |
} | |
trait AsyncKmsService { | |
type Key | |
val executor: ExecutionContext | |
def getKey(key: String): Future[Key] | |
} | |
case class KmsEncryptedString[S <: State](value: String, key: String) | |
object KmsEncryptedString { | |
implicit val encryptableAsync: Encryptable[KmsEncryptedString, AsyncKmsService, Future] = new Encryptable[KmsEncryptedString, AsyncKmsService, Future] { | |
def encrypt[S <: Decrypted](i: KmsEncryptedString[S], dep: AsyncKmsService): Future[KmsEncryptedString[Encrypted]] = { | |
dep.getKey(i.key).map { key => | |
i.copy[Encrypted](value = i.value + key) | |
}(dep.executor) | |
} | |
def decrypt[S <: Encrypted](i: KmsEncryptedString[S], dep: AsyncKmsService): Future[KmsEncryptedString[Decrypted]] = { | |
dep.getKey(i.key).map { key => | |
i.copy[Decrypted]() | |
}(dep.executor) | |
} | |
} | |
// implicit val encryptable: Encryptable[KmsEncryptedString, KmsService, Try] = new Encryptable[KmsEncryptedString, KmsService, Try] { | |
// def encrypt[S <: Decrypted](i: KmsEncryptedString[S], dep: AsyncKmsService): Try[KmsEncryptedString[Encrypted]] = { | |
// val key = dep.getKey(i.key) | |
// println("Yay I have a KmsService") | |
// Success(i.copy[Encrypted](value = i.value + key)) | |
// } | |
// def decrypt[S <: Encrypted](i: KmsEncryptedString[S], dep: AsyncKmsService): Try[KmsEncryptedString[Decrypted]] = { | |
// Success(i.copy[Decrypted]()) | |
// } | |
// } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: