Last active
          April 4, 2018 23:17 
        
      - 
      
- 
        Save pshirshov/ffdd7558030082580ebbd896f626ecaf to your computer and use it in GitHub Desktop. 
    IDL: services model
  
        
  
    
      This file contains hidden or 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 com.github.pshirshov.izumi.idealingua.runtime.services | |
| import scala.concurrent.{ExecutionContext, Future} | |
| import scala.util.Try | |
| import scala.language.{higherKinds, implicitConversions} | |
| //-------------------------------------------------------------------------- | |
| // Runtime: unopinionated part | |
| trait ServiceResult[R[_]] { | |
| @inline def map[A, B](r: R[A])(f: A => B): R[B] | |
| @inline def flatMap[A, B](r: R[A])(f: A => R[B]): R[B] | |
| @inline def pure[A](v: => A): R[A] | |
| } | |
| object ServiceResult { | |
| type Id[T] = T | |
| @inline implicit def toOps[R[_], A](value: R[A]): ServiceResultOps[R, A] = new ServiceResultOps[R, A](value) | |
| class ServiceResultOps[R[_], A](val value: R[A]) extends AnyVal { | |
| @inline def map[B](f: A => B)(implicit serviceResult: ServiceResult[R]): R[B] = serviceResult.map(value)(f) | |
| @inline def flatMap[B](f: A => R[B])(implicit serviceResult: ServiceResult[R]): R[B] = serviceResult.flatMap(value)(f) | |
| } | |
| implicit object ServiceResultId extends ServiceResult[Id] { | |
| @inline override def map[A, B](r: Id[A])(f: A => B) = f(r) | |
| @inline override def flatMap[A, B](fa: Id[A])(f: A => Id[B]): Id[B] = f(fa) | |
| @inline override def pure[A](v: => A): Id[A] = v | |
| } | |
| implicit object ServiceResultOption extends ServiceResult[Option] { | |
| @inline override def map[A, B](r: Option[A])(f: A => B): Option[B] = r.map(f) | |
| @inline override def flatMap[A, B](r: Option[A])(f: A => Option[B]): Option[B] = r.flatMap(f) | |
| @inline override def pure[A](v: => A): Option[A] = Option(v) | |
| } | |
| implicit object ServiceResultTry extends ServiceResult[Try] { | |
| @inline override def map[A, B](r: Try[A])(f: A => B): Try[B] = r.map(f) | |
| @inline override def flatMap[A, B](r: Try[A])(f: A => Try[B]): Try[B] = r.flatMap(f) | |
| @inline override def pure[A](v: => A): Try[A] = Try(v) | |
| } | |
| implicit def toServiceResultFutureOps(implicit ec: ExecutionContext): ServiceResultFuture = new ServiceResultFuture | |
| class ServiceResultFuture(implicit ec: ExecutionContext) extends ServiceResult[Future] { | |
| @inline override def map[A, B](r: Future[A])(f: A => B): Future[B] = r.map(f) | |
| @inline override def flatMap[A, B](r: Future[A])(f: A => Future[B]): Future[B] = r.flatMap(f) | |
| @inline override def pure[A](v: => A): Future[A] = Future(v) | |
| } | |
| } | |
| trait ServiceResultTransformer[R1[_], R2[_]] { | |
| def transform[A](r: R1[A]): R2[A] | |
| } | |
| object ServiceResultTransformer { | |
| implicit val transformId: ServiceResultTransformer[ServiceResult.Id, ServiceResult.Id] = new ServiceResultTransformerId[ServiceResult.Id] | |
| implicit val transformTry: ServiceResultTransformer[Try, Try] = new ServiceResultTransformerId[Try] | |
| implicit val transformOption: ServiceResultTransformer[Option, Option] = new ServiceResultTransformerId[Option] | |
| implicit val transformFuture: ServiceResultTransformer[Future, Future] = new ServiceResultTransformerId[Future] | |
| class ServiceResultTransformerId[R[_]] extends ServiceResultTransformer[R, R] { | |
| override def transform[A](r: R[A]): R[A] = r | |
| } | |
| } | |
| trait WithResultType[R[_]] { | |
| type Result[T] = R[T] | |
| } | |
| trait WithResult[R[_]] extends WithResultType[R] { | |
| protected def _ServiceResult: ServiceResult[R] | |
| protected def _Result[T](value: => T): R[T] = _ServiceResult.pure(value) | |
| } | |
| trait Marshaller[Value, Marshalled] { | |
| def encode(v: Value): Marshalled | |
| } | |
| trait Unmarshaller[Marshalled, Value] { | |
| def decode(v: Marshalled): Value | |
| } | |
| trait Transport[RequestWire, ResponseWire] { | |
| def send(v: RequestWire): ResponseWire | |
| } | |
| trait TransportMarshallers[RequestWire, Request, ResponseWire, Response] { | |
| val requestUnmarshaller: Unmarshaller[RequestWire, Request] | |
| val requestMarshaller: Marshaller[Request, RequestWire] | |
| val responseMarshaller: Marshaller[Response, ResponseWire] | |
| val responseUnmarshaller: Unmarshaller[ResponseWire, Response] | |
| } | |
| trait Dispatcher[In, Out, R[_]] extends WithResultType[R] { | |
| def dispatch(input: In): Result[Out] | |
| } | |
| trait Receiver[In, Out, R[_]] extends WithResultType[R] { | |
| def receive(input: In): Result[Out] | |
| } | |
| //-------------------------------------------------------------------------- | |
| // Runtime: opinionated part | |
| class ServerReceiver[RequestWire, Request, ResponseWire, Response, R[_] : ServiceResult] | |
| ( | |
| dispatcher: Dispatcher[Request, Response, R] | |
| , bindings: TransportMarshallers[RequestWire, Request, ResponseWire, Response] | |
| ) extends Receiver[RequestWire, ResponseWire, R] with WithResult[R] { | |
| override protected def _ServiceResult: ServiceResult[R] = implicitly | |
| def receive(request: RequestWire): R[ResponseWire] = { | |
| import ServiceResult._ | |
| _Result(bindings.requestUnmarshaller.decode(request)) | |
| .flatMap(dispatcher.dispatch) | |
| .map(bindings.responseMarshaller.encode) | |
| } | |
| } | |
| class ClientDispatcher[RequestWire, Request, ResponseWire, Response, R[_] : ServiceResult] | |
| ( | |
| transport: Transport[RequestWire, R[ResponseWire]] | |
| , bindings: TransportMarshallers[RequestWire, Request, ResponseWire, Response] | |
| ) extends Dispatcher[Request, Response, R] with WithResult[R] { | |
| override protected def _ServiceResult: ServiceResult[R] = implicitly | |
| def dispatch(input: Request): Result[Response] = { | |
| import ServiceResult._ | |
| _Result(bindings.requestMarshaller.encode(input)) | |
| .flatMap(transport.send) | |
| .map(bindings.responseUnmarshaller.decode) | |
| } | |
| } | |
| //-------------------------------------------------------------------------- | |
| // Generated part | |
| trait GreeterService[R[_]] extends WithResultType[R] { | |
| def greet(name: String, surname: String): Result[String] | |
| } | |
| trait GreeterServiceWrapped[R[_]] extends WithResultType[R] { | |
| import GreeterServiceWrapped._ | |
| def greet(input: GreetInput): Result[GreetOutput] | |
| } | |
| object GreeterServiceWrapped { | |
| sealed trait GreeterServiceInput | |
| case class GreetInput(name: String, surname: String) extends GreeterServiceInput | |
| sealed trait GreeterServiceOutput | |
| case class GreetOutput(value: String) extends GreeterServiceOutput | |
| trait GreeterServiceDispatcherPacking[R[_]] extends GreeterService[R] with WithResult[R] { | |
| def dispatcher: Dispatcher[GreeterServiceInput, GreeterServiceOutput, R] | |
| def greet(name: String, surname: String): Result[String] = { | |
| val packed = GreetInput(name, surname) | |
| val dispatched = dispatcher.dispatch(packed) | |
| _ServiceResult.map(dispatched) { | |
| case o: GreetOutput => | |
| o.value | |
| } | |
| } | |
| } | |
| object GreeterServiceDispatcherPacking { | |
| class Impl[R[_] : ServiceResult](val dispatcher: Dispatcher[GreeterServiceInput, GreeterServiceOutput, R]) extends GreeterServiceDispatcherPacking[R] { | |
| override protected def _ServiceResult: ServiceResult[R] = implicitly | |
| } | |
| } | |
| trait GreeterServiceDispatcherUnpacking[R[_]] extends GreeterServiceWrapped[R] with Dispatcher[GreeterServiceInput, GreeterServiceOutput, R] with WithResult[R] { | |
| def service: GreeterService[R] | |
| override def greet(input: GreetInput): Result[GreetOutput] = { | |
| val result = service.greet(input.name, input.surname) | |
| _ServiceResult.map(result)(GreetOutput) | |
| } | |
| def dispatch(input: GreeterServiceInput): Result[GreeterServiceOutput] = { | |
| input match { | |
| case v: GreetInput => | |
| _ServiceResult.map(greet(v))(v => v) // upcast | |
| } | |
| } | |
| } | |
| object GreeterServiceDispatcherUnpacking { | |
| class Impl[R[_] : ServiceResult](val service: GreeterService[R]) extends GreeterServiceDispatcherUnpacking[R] { | |
| override protected def _ServiceResult: ServiceResult[R] = implicitly | |
| } | |
| } | |
| } | |
| //-------------------------------------------------------------------------- | |
| // setup context and use | |
| trait AbstractGreeterServer[R[_]] extends GreeterService[R] with WithResult[R] { | |
| override def greet(name: String, surname: String): Result[String] = _Result { | |
| s"Hi, $name $surname!" | |
| } | |
| } | |
| object AbstractGreeterServer { | |
| class Impl[R[_] : ServiceResult] extends AbstractGreeterServer[R] { | |
| override protected def _ServiceResult: ServiceResult[R] = implicitly | |
| } | |
| } | |
| class TrivialAppTransport[I, O, R[_]](server: Receiver[I, O, R]) extends Transport[I, R[O]] { | |
| def send(v: I): R[O] = server.receive(v) | |
| } | |
| class PseudoNetwork[I, O, R[_], RT[_]](transport: Transport[I, R[O]])(implicit converter: ServiceResultTransformer[R, RT]) extends Transport[I, RT[O]] { | |
| def send(v: I): RT[O] = { | |
| val sent = transport.send(v) | |
| converter.transform(sent) | |
| } | |
| } | |
| import GreeterServiceWrapped._ | |
| object Test { | |
| type GSMarshaler = TransportMarshallers[GreeterServiceInput, GreeterServiceInput, GreeterServiceOutput, GreeterServiceOutput] | |
| class PseudoMarshallers extends GSMarshaler { | |
| override val requestUnmarshaller: Unmarshaller[GreeterServiceInput, GreeterServiceInput] = (v: GreeterServiceInput) => v | |
| override val requestMarshaller: Marshaller[GreeterServiceInput, GreeterServiceInput] = (v: GreeterServiceInput) => v | |
| override val responseMarshaller: Marshaller[GreeterServiceOutput, GreeterServiceOutput] = (v: GreeterServiceOutput) => v | |
| override val responseUnmarshaller: Unmarshaller[GreeterServiceOutput, GreeterServiceOutput] = (v: GreeterServiceOutput) => v | |
| } | |
| class FailingMarshallers extends GSMarshaler { | |
| override val requestUnmarshaller: Unmarshaller[GreeterServiceInput, GreeterServiceInput] = (v: GreeterServiceInput) => ??? | |
| override val requestMarshaller: Marshaller[GreeterServiceInput, GreeterServiceInput] = (v: GreeterServiceInput) => ??? | |
| override val responseMarshaller: Marshaller[GreeterServiceOutput, GreeterServiceOutput] = (v: GreeterServiceOutput) => ??? | |
| override val responseUnmarshaller: Unmarshaller[GreeterServiceOutput, GreeterServiceOutput] = (v: GreeterServiceOutput) => ??? | |
| } | |
| class SimpleDemo[R[_] : ServiceResult] | |
| ( | |
| marshalling: GSMarshaler | |
| ) { | |
| val service = new AbstractGreeterServer.Impl[R] | |
| val serverDispatcher = new GreeterServiceWrapped.GreeterServiceDispatcherUnpacking.Impl(service) | |
| val server = new ServerReceiver(serverDispatcher, marshalling) | |
| val appTransport = new TrivialAppTransport(server) | |
| val clientDispatcher = new ClientDispatcher(appTransport, marshalling) | |
| val client = new GreeterServiceWrapped.GreeterServiceDispatcherPacking.Impl(clientDispatcher) | |
| } | |
| class ConvertingDemo[R[_] : ServiceResult, RT[_] : ServiceResult] | |
| ( | |
| marshalling: GSMarshaler | |
| ) | |
| ( | |
| implicit converter: ServiceResultTransformer[RT, R] | |
| , converter1: ServiceResultTransformer[R, RT] | |
| ) { | |
| val service = new AbstractGreeterServer.Impl[R] | |
| val serverDispatcher = new GreeterServiceWrapped.GreeterServiceDispatcherUnpacking.Impl(service) | |
| val server = new ServerReceiver(serverDispatcher, marshalling) | |
| val serverAppTransport = new TrivialAppTransport(server) | |
| val serverNetwork: Transport[GreeterServiceInput, RT[GreeterServiceOutput]] = new PseudoNetwork[GreeterServiceInput, GreeterServiceOutput, R, RT](serverAppTransport) | |
| val clientNetwork: Transport[GreeterServiceInput, R[GreeterServiceOutput]] = new PseudoNetwork[GreeterServiceInput, GreeterServiceOutput, RT, R](serverNetwork) | |
| val clientDispatcher = new ClientDispatcher(clientNetwork, marshalling) | |
| val client = new GreeterServiceWrapped.GreeterServiceDispatcherPacking.Impl(clientDispatcher) | |
| } | |
| private def testSimple(marshalling: GSMarshaler): Unit = { | |
| { | |
| val demo = new SimpleDemo[Try](marshalling) | |
| val result = demo.client.greet("John", "Doe") | |
| println(result) | |
| } | |
| { | |
| import ExecutionContext.Implicits._ | |
| val demo = new SimpleDemo[Future](marshalling) | |
| val result = demo.client.greet("John", "Doe") | |
| Thread.sleep(100) | |
| println(result) | |
| } | |
| { | |
| val demo = new SimpleDemo[Option](marshalling) | |
| val result = demo.client.greet("John", "Doe") | |
| println(result) | |
| } | |
| } | |
| private def testConverting(marshalling: GSMarshaler): Unit = { | |
| import ServiceResultTransformer._ | |
| { | |
| val demo = new ConvertingDemo[Try, Try](marshalling) | |
| val result = demo.client.greet("John", "Doe") | |
| println(result) | |
| } | |
| { | |
| import ExecutionContext.Implicits._ | |
| val demo = new ConvertingDemo[Future, Future](marshalling) | |
| val result = demo.client.greet("John", "Doe") | |
| Thread.sleep(100) | |
| println(result) | |
| } | |
| { | |
| val demo = new ConvertingDemo[Option, Option](marshalling) | |
| val result = demo.client.greet("John", "Doe") | |
| println(result) | |
| } | |
| } | |
| def main(args: Array[String]): Unit = { | |
| testSimple(new PseudoMarshallers()) | |
| testConverting(new PseudoMarshallers()) | |
| println(Try(testSimple(new FailingMarshallers()))) | |
| println(Try(testConverting(new FailingMarshallers()))) | |
| } | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment