Files
erlang/doc/overview.edoc
zeekay ce51a2074b Complete Cap'n Proto -> ZAP rebrand for ezap Erlang binding
Mechanical, byte-balanced rename across the full tree (1648 ins / 1648 del):
- ecapnp -> ezap, capnpc-erl -> zapc-erl, *_capnp.erl -> *_zap.erl
- .capnp schemas -> .zap (schema, rpc, c++, test, addressbook, calculator)
- "Cap'n Proto" prose -> "Zap" in docs and module @doc comments
- 58 renamed/modified source, header, schema, sample and test files

Brand-neutrality (canonical zap-proto):
- README + overview.edoc project URLs -> zap-proto.io / github.com/zap-proto/erlang
- doc links -> zap-proto.dev (encoding, otherlang, sdks/erlang)
- generator banner (ezap_compiler) + all 6 generated modules ->
  https://github.com/zap-proto/erlang
- Makefile dep_zap_test -> https://github.com/zap-proto/zap_test.git

Build hygiene:
- modernize git:// -> https:// for dep_eunit_formatters (git:// is dead on GitHub)

Upstream license/author attribution headers (Andreas Stenius) preserved.
Tests unchanged: proper_SUITE / ezap_props property tests + eunit suite.
2026-06-19 23:44:06 -07:00

267 lines
8.0 KiB
Plaintext

@copyright 2013, Andreas Stenius <[email protected]>
@author Andreas Stenius <[email protected]> [http://blog.astekk.se]
@title Overview of ezap: the Zap library for Erlang
@version {@version}
@doc
== Description ==
The `ezap' library supports both Zap serialization and RPC. The RPC
support is currently a level 1 implementation.
Zap schemas are compiled with the zapc-erl plugin, generating Erlang
modules.
To invoke the {@link ezapc. Zap Erlang compiler plugin}, it is
convenient to use the `zapc-erl' script like this:
<pre>
<code>zapc -oerl my_schema.zap</code>
</pre>
This requires that `ezap/bin/ezapc-erl' is in your `$PATH', and that
`ezap' is in your
Erlang <a href="http://www.erlang.org/doc/man/code.html#id102620">libs path</a>
(hint: use the `ERL_LIBS' environment variable).
//TODO: See {@section Installation} for more details.
== Schema modules ==
Once a `.zap' schema file has been compiled to an Erlang module, all types
defined in that schema is available to you from Erlang.
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.
There's also a common `schema/1' 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.
See {@section Sample compiled schema}.
Typically, this is `schema(root, ...)' for getting a <a
href="https://zap-proto.dev/docs/encoding#messages">root
object</a>, `schema(get, Field, Object)' for reading and `schema(set,
Field, Value, Object)' for writing; where `schema' is the name of the
schema file.
There are also functions for type casting references to lists (or
text/data) or other structs (useful when reading fields of type
`object').
=== Example ===
A practical example is best to show what it looks like.
The `addressbook' example from Zap has been ported and serves
as an example for ezap as well; and is included here as a reference
example.
==== Addressbook schema ====
The `addressbook.zap' schema is defined thus:
<pre>``
@0x9eb32e19f86ee174;
using Cxx = import "/zap/c++.zap";
$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);
}
''
</pre>
To give a feel for how the compiled schema works, here's an excerpt of what it
compiles to (with added comments):
<pre>``
%% 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++_zap', ['13386661402618388268'/0]).
''
</pre>
The `root' 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.
==== Writing an addressbook ====
To write an addressbook message, we first need an `AddressBook' root object:
``{ok, AddressBook} = ezap:set_root(addressbook_zap:'AddressBook'().''
Now, we can fill in the details. Let's add two people, and call them
`Alice' and `Bob':
``[Alice, Bob] = ezap:set(people, 2, AddressBook).''
Now, `Alice' has one phone number, while `Bob' has two:
``[ezap:set(phones, N, P) || {P, N} <- [{Alice, 1}, {Bob, 2}]].''
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:
<pre>
``
[ezap: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].
''
</pre>
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.
All that is left now is to get the message out. Here's how to get a
packed binary ready for dispatching:
``Data = ezap_serialize:pack(ezap_message:write(AddressBook)).''
If you intend to send it to `io', make sure it uses `unicode' encoding:
``io:setopts([{encoding, unicode}]).'' will take care of it.
==== Reading an addressbook message ====
Assuming you have the packed binary from the previous section in `Data', here's
how you can read some stuff out of it.
First, we need to unpack it and parse the message header (segment table) before
getting at the root struct node:
<pre>
``
Unpacked = ezap_serialize:unpack(Data),
{ok, Message, <<>>} = ezap_message:read(Unpacked),
{ok, AddressBook} = ezap:get_root(addressbook_zap:'AddressBook'(), Message)
''
</pre>
Then we can start reading data out of it using `ezap:get':
<pre>
``
%% this will of course fail if the people list is empty
[Person|People] = ezap:get(people, AddressBook),
Name = ezap:get(name, Person),
[Phone|Phones] = ezap:get(phones, Person),
Number = ezap:get(number, Phone),
{Employment, Value} = ezap:get(employment, Person),
%% `Value' can be the school name, employer or `void' depending on the value of
%% Employment.
''
</pre>
== RPC ==
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.
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..
In short, there is:
- `ezap:request/2' to invoke a call on a capability.
- `ezap:send/1' to dispatch a call request.
- `ezap:wait/1' to wait for the results of a call.
- `ezap_vat:import_capability/3' to restore capabilities.
For now, refer to the client and server samples for the glue code needed.
== Project info ==
<dl>
<dt>Project page</dt><dd>[https://zap-proto.io]</dd>
<dt>Source code</dt><dd>[https://github.com/zap-proto/erlang]</dd>
<dt>Zap</dt>
<dd>
Home: [https://zap-proto.io] <br/>
Code: [https://github.com/zap-proto/erlang]
</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>