cannam@133: # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@133: # Licensed under the MIT License: cannam@133: # cannam@133: # Permission is hereby granted, free of charge, to any person obtaining a copy cannam@133: # of this software and associated documentation files (the "Software"), to deal cannam@133: # in the Software without restriction, including without limitation the rights cannam@133: # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@133: # copies of the Software, and to permit persons to whom the Software is cannam@133: # furnished to do so, subject to the following conditions: cannam@133: # cannam@133: # The above copyright notice and this permission notice shall be included in cannam@133: # all copies or substantial portions of the Software. cannam@133: # cannam@133: # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@133: # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@133: # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@133: # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@133: # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@133: # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@133: # THE SOFTWARE. cannam@133: cannam@133: @0x85150b117366d14b; cannam@133: cannam@133: interface Calculator { cannam@133: # A "simple" mathematical calculator, callable via RPC. cannam@133: # cannam@133: # But, to show off Cap'n Proto, we add some twists: cannam@133: # cannam@133: # - You can use the result from one call as the input to the next cannam@133: # without a network round trip. To accomplish this, evaluate() cannam@133: # returns a `Value` object wrapping the actual numeric value. cannam@133: # This object may be used in a subsequent expression. With cannam@133: # promise pipelining, the Value can actually be used before cannam@133: # the evaluate() call that creates it returns! cannam@133: # cannam@133: # - You can define new functions, and then call them. This again cannam@133: # shows off pipelining, but it also gives the client the cannam@133: # opportunity to define a function on the client side and have cannam@133: # the server call back to it. cannam@133: # cannam@133: # - The basic arithmetic operators are exposed as Functions, and cannam@133: # you have to call getOperator() to obtain them from the server. cannam@133: # This again demonstrates pipelining -- using getOperator() to cannam@133: # get each operator and then using them in evaluate() still cannam@133: # only takes one network round trip. cannam@133: cannam@133: evaluate @0 (expression :Expression) -> (value :Value); cannam@133: # Evaluate the given expression and return the result. The cannam@133: # result is returned wrapped in a Value interface so that you cannam@133: # may pass it back to the server in a pipelined request. To cannam@133: # actually get the numeric value, you must call read() on the cannam@133: # Value -- but again, this can be pipelined so that it incurs cannam@133: # no additional latency. cannam@133: cannam@133: struct Expression { cannam@133: # A numeric expression. cannam@133: cannam@133: union { cannam@133: literal @0 :Float64; cannam@133: # A literal numeric value. cannam@133: cannam@133: previousResult @1 :Value; cannam@133: # A value that was (or, will be) returned by a previous cannam@133: # evaluate(). cannam@133: cannam@133: parameter @2 :UInt32; cannam@133: # A parameter to the function (only valid in function bodies; cannam@133: # see defFunction). cannam@133: cannam@133: call :group { cannam@133: # Call a function on a list of parameters. cannam@133: function @3 :Function; cannam@133: params @4 :List(Expression); cannam@133: } cannam@133: } cannam@133: } cannam@133: cannam@133: interface Value { cannam@133: # Wraps a numeric value in an RPC object. This allows the value cannam@133: # to be used in subsequent evaluate() requests without the client cannam@133: # waiting for the evaluate() that returns the Value to finish. cannam@133: cannam@133: read @0 () -> (value :Float64); cannam@133: # Read back the raw numeric value. cannam@133: } cannam@133: cannam@133: defFunction @1 (paramCount :Int32, body :Expression) cannam@133: -> (func :Function); cannam@133: # Define a function that takes `paramCount` parameters and returns the cannam@133: # evaluation of `body` after substituting these parameters. cannam@133: cannam@133: interface Function { cannam@133: # An algebraic function. Can be called directly, or can be used inside cannam@133: # an Expression. cannam@133: # cannam@133: # A client can create a Function that runs on the server side using cannam@133: # `defFunction()` or `getOperator()`. Alternatively, a client can cannam@133: # implement a Function on the client side and the server will call back cannam@133: # to it. However, a function defined on the client side will require a cannam@133: # network round trip whenever the server needs to call it, whereas cannam@133: # functions defined on the server and then passed back to it are called cannam@133: # locally. cannam@133: cannam@133: call @0 (params :List(Float64)) -> (value :Float64); cannam@133: # Call the function on the given parameters. cannam@133: } cannam@133: cannam@133: getOperator @2 (op :Operator) -> (func :Function); cannam@133: # Get a Function representing an arithmetic operator, which can then be cannam@133: # used in Expressions. cannam@133: cannam@133: enum Operator { cannam@133: add @0; cannam@133: subtract @1; cannam@133: multiply @2; cannam@133: divide @3; cannam@133: } cannam@133: }