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