# 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. @0x85150b117366d14b; interface Calculator { # A "simple" mathematical calculator, callable via RPC. # # But, to show off Cap'n Proto, we add some twists: # # - You can use the result from one call as the input to the next # without a network round trip. To accomplish this, evaluate() # returns a `Value` object wrapping the actual numeric value. # This object may be used in a subsequent expression. With # promise pipelining, the Value can actually be used before # the evaluate() call that creates it returns! # # - You can define new functions, and then call them. This again # shows off pipelining, but it also gives the client the # opportunity to define a function on the client side and have # the server call back to it. # # - The basic arithmetic operators are exposed as Functions, and # you have to call getOperator() to obtain them from the server. # This again demonstrates pipelining -- using getOperator() to # get each operator and then using them in evaluate() still # only takes one network round trip. evaluate @0 (expression :Expression) -> (value :Value); # Evaluate the given expression and return the result. The # result is returned wrapped in a Value interface so that you # may pass it back to the server in a pipelined request. To # actually get the numeric value, you must call read() on the # Value -- but again, this can be pipelined so that it incurs # no additional latency. struct Expression { # A numeric expression. union { literal @0 :Float64; # A literal numeric value. previousResult @1 :Value; # A value that was (or, will be) returned by a previous # evaluate(). parameter @2 :UInt32; # A parameter to the function (only valid in function bodies; # see defFunction). call :group { # Call a function on a list of parameters. function @3 :Function; params @4 :List(Expression); } } } interface Value { # Wraps a numeric value in an RPC object. This allows the value # to be used in subsequent evaluate() requests without the client # waiting for the evaluate() that returns the Value to finish. read @0 () -> (value :Float64); # Read back the raw numeric value. } defFunction @1 (paramCount :Int32, body :Expression) -> (func :Function); # Define a function that takes `paramCount` parameters and returns the # evaluation of `body` after substituting these parameters. interface Function { # An algebraic function. Can be called directly, or can be used inside # an Expression. # # A client can create a Function that runs on the server side using # `defFunction()` or `getOperator()`. Alternatively, a client can # implement a Function on the client side and the server will call back # to it. However, a function defined on the client side will require a # network round trip whenever the server needs to call it, whereas # functions defined on the server and then passed back to it are called # locally. call @0 (params :List(Float64)) -> (value :Float64); # Call the function on the given parameters. } getOperator @2 (op :Operator) -> (func :Function); # Get a Function representing an arithmetic operator, which can then be # used in Expressions. enum Operator { add @0; subtract @1; multiply @2; divide @3; } }