text: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
  // Licensed under the MIT License:
  //
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  //
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  
  #include "calculator.capnp.h"
  #include <kj/debug.h>
  #include <capnp/ez-rpc.h>
  #include <capnp/message.h>
  #include <iostream>
  
  typedef unsigned int uint;
  
  kj::Promise<double> readValue(Calculator::Value::Client value) {
    // Helper function to asynchronously call read() on a Calculator::Value and
    // return a promise for the result.  (In the future, the generated code might
    // include something like this automatically.)
  
    return value.readRequest().send()
        .then([](capnp::Response<Calculator::Value::ReadResults> result) {
      return result.getValue();
    });
  }
  
  kj::Promise<double> evaluateImpl(
      Calculator::Expression::Reader expression,
      capnp::List<double>::Reader params = capnp::List<double>::Reader()) {
    // Implementation of CalculatorImpl::evaluate(), also shared by
    // FunctionImpl::call().  In the latter case, `params` are the parameter
    // values passed to the function; in the former case, `params` is just an
    // empty list.
  
    switch (expression.which()) {
      case Calculator::Expression::LITERAL:
        return expression.getLiteral();
  
      case Calculator::Expression::PREVIOUS_RESULT:
        return readValue(expression.getPreviousResult());
  
      case Calculator::Expression::PARAMETER: {
        KJ_REQUIRE(expression.getParameter() < params.size(),
                   "Parameter index out-of-range.");
        return params[expression.getParameter()];
      }
  
      case Calculator::Expression::CALL: {
        auto call = expression.getCall();
        auto func = call.getFunction();
  
        // Evaluate each parameter.
        kj::Array<kj::Promise<double>> paramPromises =
            KJ_MAP(param, call.getParams()) {
              return evaluateImpl(param, params);
            };
  
        // Join the array of promises into a promise for an array.
        kj::Promise<kj::Array<double>> joinedParams =
            kj::joinPromises(kj::mv(paramPromises));
  
        // When the parameters are complete, call the function.
        return joinedParams.then([func](kj::Array<double>&& paramValues) mutable {
          auto request = func.callRequest();
          request.setParams(paramValues);
          return request.send().then(
              [](capnp::Response<Calculator::Function::CallResults>&& result) {
            return result.getValue();
          });
        });
      }
  
      default:
        // Throw an exception.
        KJ_FAIL_REQUIRE("Unknown expression type.");
    }
  }
  
  class ValueImpl final: public Calculator::Value::Server {
    // Simple implementation of the Calculator.Value Cap'n Proto interface.
  
  public:
    ValueImpl(double value): value(value) {}
  
    kj::Promise<void> read(ReadContext context) {
      context.getResults().setValue(value);
      return kj::READY_NOW;
    }
  
  private:
    double value;
  };
  
  class FunctionImpl final: public Calculator::Function::Server {
    // Implementation of the Calculator.Function Cap'n Proto interface, where the
    // function is defined by a Calculator.Expression.
  
  public:
    FunctionImpl(uint paramCount, Calculator::Expression::Reader body)
        : paramCount(paramCount) {
      this->body.setRoot(body);
    }
  
    kj::Promise<void> call(CallContext context) {
      auto params = context.getParams().getParams();
      KJ_REQUIRE(params.size() == paramCount, "Wrong number of parameters.");
  
      return evaluateImpl(body.getRoot<Calculator::Expression>(), params)
          .then([context](double value) mutable {
        context.getResults().setValue(value);
      });
    }
  
  private:
    uint paramCount;
    // The function's arity.
  
    capnp::MallocMessageBuilder body;
    // Stores a permanent copy of the function body.
  };
  
  class OperatorImpl final: public Calculator::Function::Server {
    // Implementation of the Calculator.Function Cap'n Proto interface, wrapping
    // basic binary arithmetic operators.
  
  public:
    OperatorImpl(Calculator::Operator op): op(op) {}
  
    kj::Promise<void> call(CallContext context) {
      auto params = context.getParams().getParams();
      KJ_REQUIRE(params.size() == 2, "Wrong number of parameters.");
  
      double result;
      switch (op) {
        case Calculator::Operator::ADD:     result = params[0] + params[1]; break;
        case Calculator::Operator::SUBTRACT:result = params[0] - params[1]; break;
        case Calculator::Operator::MULTIPLY:result = params[0] * params[1]; break;
        case Calculator::Operator::DIVIDE:  result = params[0] / params[1]; break;
        default:
          KJ_FAIL_REQUIRE("Unknown operator.");
      }
  
      context.getResults().setValue(result);
      return kj::READY_NOW;
    }
  
  private:
    Calculator::Operator op;
  };
  
  class CalculatorImpl final: public Calculator::Server {
    // Implementation of the Calculator Cap'n Proto interface.
  
  public:
    kj::Promise<void> evaluate(EvaluateContext context) override {
      return evaluateImpl(context.getParams().getExpression())
          .then([context](double value) mutable {
        context.getResults().setValue(kj::heap<ValueImpl>(value));
      });
    }
  
    kj::Promise<void> defFunction(DefFunctionContext context) override {
      auto params = context.getParams();
      context.getResults().setFunc(kj::heap<FunctionImpl>(
          params.getParamCount(), params.getBody()));
      return kj::READY_NOW;
    }
  
    kj::Promise<void> getOperator(GetOperatorContext context) override {
      context.getResults().setFunc(kj::heap<OperatorImpl>(
          context.getParams().getOp()));
      return kj::READY_NOW;
    }
  };
  
  int main(int argc, const char* argv[]) {
    if (argc != 2) {
      std::cerr << "usage: " << argv[0] << " ADDRESS[:PORT]\n"
          "Runs the server bound to the given address/port.\n"
          "ADDRESS may be '*' to bind to all local addresses.\n"
          ":PORT may be omitted to choose a port automatically." << std::endl;
      return 1;
    }
  
    // Set up a server.
    capnp::EzRpcServer server(kj::heap<CalculatorImpl>(), argv[1]);
  
    // Write the port number to stdout, in case it was chosen automatically.
    auto& waitScope = server.getWaitScope();
    uint port = server.getPort().wait(waitScope);
    if (port == 0) {
      // The address format "unix:/path/to/socket" opens a unix domain socket,
      // in which case the port will be zero.
      std::cout << "Listening on Unix socket..." << std::endl;
    } else {
      std::cout << "Listening on port " << port << "..." << std::endl;
    }
  
    // Run forever, accepting connections and handling requests.
    kj::NEVER_DONE.wait(waitScope);
  }
  