mirror of
https://github.com/zap-proto/erlang.git
synced 2026-10-30 15:05:14 +00:00
271 lines
11 KiB
HTML
271 lines
11 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>Overview of ecapnp: the Cap'n Proto library for Erlang</title>
|
|
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
|
|
</head>
|
|
<body bgcolor="white">
|
|
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
|
<h1>Overview of ecapnp: the Cap'n Proto library for Erlang</h1>
|
|
<p>Copyright © 2013, Andreas Stenius <[email protected]></p>
|
|
<p><b>Version:</b> May 30 2014 12:56:29</p>
|
|
<p><b>Authors:</b> Andreas Stenius (<a href="mailto:[email protected]"><tt>[email protected]</tt></a>) [<em>web site:</em> <tt><a href="http://blog.astekk.se" target="_top">http://blog.astekk.se</a></tt>].</p>
|
|
|
|
|
|
<h3><a name="Description">Description</a></h3>
|
|
|
|
<p>The <code>ecapnp</code> library supports both Cap'n Proto serialization and RPC. The RPC
|
|
support is currently a level 1 implementation.</p>
|
|
|
|
<p>Cap'n Proto schemas are compiled with the capnpc-erl plugin, generating Erlang
|
|
modules.</p>
|
|
|
|
To invoke the <a href="ecapnpc.html">Cap'n Proto Erlang compiler plugin</a>, it is
|
|
convenient to use the <code>capnpc-erl</code> script like this:
|
|
<pre>
|
|
<code>capnpc -oerl my_schema.capnp</code>
|
|
</pre>
|
|
|
|
<p>This requires that <code>ecapnp/bin/ecapnpc-erl</code> is in your <code>$PATH</code>, and that
|
|
<code>ecapnp</code> is in your
|
|
Erlang <a href="http://www.erlang.org/doc/man/code.html#id102620">libs path</a>
|
|
(hint: use the <code>ERL_LIBS</code> environment variable).</p>
|
|
|
|
<p>//TODO: See <a href="#Installation">Installation</a> for more details.</p>
|
|
|
|
|
|
<h3><a name="Schema_modules">Schema modules</a></h3>
|
|
|
|
<p>Once a <code>.capnp</code> schema file has been compiled to an Erlang module, all types
|
|
defined in that schema is available to you from Erlang.</p>
|
|
|
|
<p>There are several ways to get the schema for a given type, depending on what you
|
|
use to find it. Each type is exported as a 0 arity function, both by its name
|
|
and by its id, as well as a 1 arity function by its name taking a list nested
|
|
type names.</p>
|
|
|
|
<p>There's also a common <code>schema/1</code> function where you can look up the schema for
|
|
any given type by name or id. Nested types are also supported by passing the
|
|
type names in a list.</p>
|
|
|
|
<p>See <a href="#Sample_compiled_schema">Sample compiled schema</a>.</p>
|
|
|
|
|
|
<p>Typically, this is <code>schema(root, ...)</code> for getting a <a href="http://kentonv.github.io/capnproto/encoding.html#messages">root
|
|
object</a>, <code>schema(get, Field, Object)</code> for reading and <code>schema(set,
|
|
Field, Value, Object)</code> for writing; where <code>schema</code> is the name of the
|
|
schema file.</p>
|
|
|
|
<p>There are also functions for type casting references to lists (or
|
|
text/data) or other structs (useful when reading fields of type
|
|
<code>object</code>).</p>
|
|
|
|
|
|
<h4><a name="Example">Example</a></h4>
|
|
|
|
<p>A practical example is best to show what it looks like. </p>
|
|
|
|
<p>The <code>addressbook</code> example from Cap'n Proto has been ported and serves
|
|
as an example for ecapnp as well; and is included here as a reference
|
|
example.</p>
|
|
|
|
<h5><a name="Addressbook_schema">Addressbook schema</a></h5>
|
|
|
|
The <code>addressbook.capnp</code> schema is defined thus:
|
|
<pre><code>@0x9eb32e19f86ee174;
|
|
|
|
using Cxx = import "/capnp/c++.capnp";
|
|
$Cxx.namespace("addressbook");
|
|
|
|
struct Person {
|
|
id @0 :UInt32;
|
|
name @1 :Text;
|
|
email @2 :Text;
|
|
phones @3 :List(PhoneNumber);
|
|
|
|
struct PhoneNumber {
|
|
number @0 :Text;
|
|
type @1 :Type;
|
|
|
|
enum Type {
|
|
mobile @0;
|
|
home @1;
|
|
work @2;
|
|
}
|
|
}
|
|
|
|
employment :union {
|
|
unemployed @4 :Void;
|
|
employer @5 :Text;
|
|
school @6 :Text;
|
|
selfEmployed @7 :Void;
|
|
# We assume that a person is only one of these.
|
|
}
|
|
}
|
|
|
|
struct AddressBook {
|
|
people @0 :List(Person);
|
|
}</code>
|
|
</pre>
|
|
|
|
To give a feel for how the compiled schema works, here's an excerpt of what it
|
|
compiles to (with added comments):
|
|
<pre><code>%% The schema file id
|
|
-vsn(11435534567900897652).
|
|
|
|
%% functions for getting the schema for any given type
|
|
-export([schema/1, 'Person'/0, 'Person'/1, '10988939875124296728'/0, '9317543775882349264'/0,
|
|
'10511609358742521391'/0, '13477914502553102653'/0, 'AddressBook'/0, 'AddressBook'/1,
|
|
'17957216978475721012'/0, root/0, root/1, '11435534567900897652'/0]).
|
|
|
|
%% a list mapping all type names with their corresponding id
|
|
-types([{10988939875124296728, 'Person'}, {9317543775882349264, ['Person', 'PhoneNumber']},
|
|
{10511609358742521391, ['Person', 'PhoneNumber', 'Type']},
|
|
{13477914502553102653, ['Person', employment]}, {17957216978475721012, 'AddressBook'},
|
|
{11435534567900897652, root}]).
|
|
|
|
%% any imported types can be seen in the source, but are not directly listed in
|
|
%% the types above, but are accessible using the `schema/1' function
|
|
-import('c++_capnp', ['13386661402618388268'/0]).</code>
|
|
</pre>
|
|
|
|
<p>The <code>root</code> type is the file level schema. It can be used to find all top-level
|
|
types as well as any annotations that applies to the schema file.</p>
|
|
|
|
|
|
<h5><a name="Writing_an_addressbook">Writing an addressbook</a></h5>
|
|
|
|
<p>To write an addressbook message, we first need an <code>AddressBook</code> root object:</p>
|
|
|
|
<p><code>{ok, AddressBook} = ecapnp:set_root(addressbook_capnp:'AddressBook'().</code></p>
|
|
|
|
<p>Now, we can fill in the details. Let's add two people, and call them
|
|
<code>Alice</code> and <code>Bob</code>:</p>
|
|
|
|
<p><code>[Alice, Bob] = ecapnp:set(people, 2, AddressBook).</code></p>
|
|
|
|
<p>Now, <code>Alice</code> has one phone number, while <code>Bob</code> has two:</p>
|
|
|
|
<p><code>[ecapnp:set(phones, N, P) || {P, N} <- [{Alice, 1}, {Bob, 2}]].</code></p>
|
|
|
|
<p>Ok, we're all set to fill in the blanks of the people and phone objects we have
|
|
allocated. We're using a list comprehension to save on some typing:</p>
|
|
|
|
<pre>
|
|
<code>[ecapnp:set(Field, Value, Obj)
|
|
|| {Obj, FieldValue} <-
|
|
[{Alice,
|
|
[{id, 123},
|
|
{name, <<"Alice">>},
|
|
{email, <<"[email protected]">>},
|
|
{employment, {shool, <<"MIT">>}},
|
|
{phones, {0, {number, <<"555-1212">>}}},
|
|
{phones, {0, {type, mobile}}}]},
|
|
{Bob,
|
|
[{id, 456},
|
|
{name, <<"Bob">>},
|
|
{email, <<"[email protected]">>},
|
|
{employment, unemployed},
|
|
{phones, {0, {number, <<"555-4567">>}}},
|
|
{phones, {0, {type, home}}},
|
|
{phones, {1, {number, <<"555-7654">>}}},
|
|
{phones, {1, {type, mobile}}}]}],
|
|
{Field, Value} <- FieldValues].</code>
|
|
</pre>
|
|
|
|
<p>Note that we could have saved a reference to the phone objects
|
|
directly and used those instead of embedding them in the calls to
|
|
Alice and Bob, when we allocated the phone objects, the same way we
|
|
saved the result when allocating people.</p>
|
|
|
|
<p>All that is left now is to get the message out. Here's how to get a
|
|
packed binary ready for dispatching:</p>
|
|
|
|
<p><code>Data = ecapnp_serialize:pack(ecapnp_message:write(AddressBook)).</code></p>
|
|
|
|
<p>If you intend to send it to <code>io</code>, make sure it uses <code>unicode</code> encoding:</p>
|
|
|
|
<p><code>io:setopts([{encoding, unicode}]).</code> will take care of it.</p>
|
|
|
|
|
|
<h5><a name="Reading_an_addressbook_message">Reading an addressbook message</a></h5>
|
|
|
|
<p>Assuming you have the packed binary from the previous section in <code>Data</code>, here's
|
|
how you can read some stuff out of it.</p>
|
|
|
|
<p>First, we need to unpack it and parse the message header (segment table) before
|
|
getting at the root struct node:</p>
|
|
|
|
<pre>
|
|
<code>Unpacked = ecapnp_serialize:unpack(Data),
|
|
{ok, Message, <<>>} = ecapnp_message:read(Unpacked),
|
|
{ok, AddressBook} = ecapnp:get_root(addressbook_capnp:'AddressBook'(), Message)</code>
|
|
</pre>
|
|
|
|
<p>Then we can start reading data out of it using <code>ecapnp:get</code>:</p>
|
|
|
|
<pre>
|
|
<code>%% this will of course fail if the people list is empty
|
|
[Person|People] = ecapnp:get(people, AddressBook),
|
|
Name = ecapnp:get(name, Person),
|
|
|
|
[Phone|Phones] = ecapnp:get(phones, Person),
|
|
Number = ecapnp:get(number, Phone),
|
|
|
|
{Employment, Value} = ecapnp:get(employment, Person),
|
|
|
|
%% `Value' can be the school name, employer or `void' depending on the value of
|
|
%% Employment.</code>
|
|
</pre>
|
|
|
|
|
|
<h3><a name="RPC">RPC</a></h3>
|
|
|
|
<p>The RPC support is at level 1 (almost). Still lacking is a bit of infrastructure
|
|
for sockets, and the reference counting/releasing is still a bit of a moving
|
|
target.</p>
|
|
|
|
<p>The calculator sample application is the best source of examples, and I won't
|
|
repeat everything here at this time, as things are still subject to change..</p>
|
|
|
|
<p>In short, there is:</p>
|
|
|
|
<p>- <code>ecapnp:request/2</code> to invoke a call on a capability.
|
|
- <code>ecapnp:send/1</code> to dispatch a call request.
|
|
- <code>ecapnp:wait/1</code> to wait for the results of a call.
|
|
- <code>ecapnp_vat:import_capability/3</code> to restore capabilities.</p>
|
|
|
|
<p>For now, refer to the client and server samples for the glue code needed.</p>
|
|
|
|
|
|
<h3><a name="Project_info">Project info</a></h3>
|
|
<dl>
|
|
<dt>Project page</dt><dd><a href="http://ecapnp.astekk.se" target="_top"><tt>http://ecapnp.astekk.se</tt></a></dd>
|
|
<dt>Source code</dt><dd><a href="http://github.com/kaos/ecapnp" target="_top"><tt>http://github.com/kaos/ecapnp</tt></a></dd>
|
|
<dt>Cap'n Proto</dt>
|
|
<dd>
|
|
Home: <a href="http://capnproto.com" target="_top"><tt>http://capnproto.com</tt></a> <br>
|
|
Code: <a href="http://github.com/kentonv/capnproto" target="_top"><tt>http://github.com/kentonv/capnproto</tt></a>
|
|
</dd>
|
|
<dt>License</dt><dd>
|
|
<pre>Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.</pre>
|
|
</dd>
|
|
</dl>
|
|
|
|
<hr>
|
|
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
|
<p><i>Generated by EDoc, May 30 2014, 12:56:29.</i></p>
|
|
</body>
|
|
</html>
|