summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-04-01 14:14:32 -0400
committerDavid Robillard <d@drobilla.net>2021-04-01 14:14:32 -0400
commitec134d2c5f2c44a602ede280f9ce7dffd64caf41 (patch)
tree873f615a95280a860ae6f15254381bb3c7a920b6
parent91945867cfee9e92df50149311d98eda41b16a60 (diff)
downloadsratom-ec134d2c5f2c44a602ede280f9ce7dffd64caf41.tar.gz
sratom-ec134d2c5f2c44a602ede280f9ce7dffd64caf41.tar.bz2
sratom-ec134d2c5f2c44a602ede280f9ce7dffd64caf41.zip
WIP
-rw-r--r--bindings/cpp/meson.build8
-rw-r--r--doc/c/overview.rst263
-rw-r--r--doc/c/xml/meson.build8
-rw-r--r--doc/meson.build2
-rw-r--r--meson.build11
5 files changed, 278 insertions, 14 deletions
diff --git a/bindings/cpp/meson.build b/bindings/cpp/meson.build
index 02f4d53..ea6d336 100644
--- a/bindings/cpp/meson.build
+++ b/bindings/cpp/meson.build
@@ -17,6 +17,7 @@ if get_option('strict')
'-Wno-inline',
'-Wno-multiple-inheritance',
'-Wno-padded',
+ '-Wno-parentheses',
'-Wno-suggest-attribute=pure',
'-Wno-switch-default',
'-Wno-unused-const-variable',
@@ -39,6 +40,10 @@ else
cpp_suppressions += [
'-Wno-nullability-extension',
]
+ elif cpp.get_id() == 'gcc'
+ cpp_suppressions += [
+ '-Wno-parentheses',
+ ]
endif
endif
@@ -49,7 +54,8 @@ cpp_headers = [
]
serdpp_dep = dependency('serdxx-1',
- version: '>= 1.0.0')
+ version: '>= 1.0.0',
+ fallback: ['serd', 'serdxx_dep'])
sratompp_dep = declare_dependency(
include_directories: include_directories(['include']),
diff --git a/doc/c/overview.rst b/doc/c/overview.rst
index b5d75c1..2ffcfd1 100644
--- a/doc/c/overview.rst
+++ b/doc/c/overview.rst
@@ -1,12 +1,267 @@
-########
-Overview
-########
+############
+Using Sratom
+############
.. default-domain:: c
.. highlight:: c
-The entire API is declared in ``sratom.h``:
+The sratom API is declared in ``sratom.h``:
.. code-block:: c
#include <sratom/sratom.h>
+
+Sratom supports two operations:
+writing atoms to a model or string, called "dumping",
+and reading atoms from a model or string, called "loading".
+Each is supported by a separate object.
+
+*************
+Dumping Atoms
+*************
+
+Dumping atoms is supported by :struct:`SratomDumper`.
+A new dumper can be allocated with :func:`sratom_dumper_new`.
+It requires a :struct:`SerdWorld`,
+and both a URID map (to map vocabulary during setup),
+and URID unmap (for expanding URIDs in the output).
+For example, assuming these are already set up appropriately in the application:
+
+.. code-block:: c
+
+ SerdWorld* world = my_world();
+ LV2_URID_Map* map = my_urid_map();
+ LV2_URID_Unmap* unmap = my_urid_map();
+ SratomDumper* dumper = sratom_dumper_new(world, map, unmap);
+
+Dumping Strings
+===============
+
+Once a dumper is allocated it can be used to write any number of atoms.
+The simplest function to use is :func:`sratom_to_string`,
+which takes an environment and an atom,
+and returns a newly allocated string representation of the atom.
+
+The environment can be used to set up the base URI and any namespace prefixes for the output.
+The base URI is used to convert relative paths to URIs,
+and prefixes will be used to abbreviate the output.
+Typically, the base URI is a file URI that points to a directory that file paths are relative to,
+and prefixes are set for commonly used vocabularies.
+For example:
+
+.. code-block:: c
+
+ SerdStringView base = SERD_STATIC_STRING("file:///tmp/state/");
+ SerdEnv* env = serd_env_new(base);
+
+ serd_env_set_prefix(
+ env,
+ SERD_STATIC_STRING("atom"),
+ SERD_STATIC_STRING("http://lv2plug.in/ns/ext/atom#"));
+
+With the environment configured,
+:func:`sratom_to_string` can be used to convert atoms to strings:
+
+.. code-block:: c
+
+ LV2_Atom* atom = my_atom();
+ char* string = sratom_to_string(dumper, env, atom, 0);
+
+ fprintf(stderr, "Atom: %s\n", string);
+
+ sratom_free(string);
+
+Dumping to a Statement Sink
+===========================
+
+More advanced use cases are supported by the more fundamental functions :func:`sratom_dump` and :func:`sratom_dump_atom`.
+These write a series of statements that describe the atom to a :struct:`SerdSink`,
+which can be configured to write anywhere, such as a file or model.
+A subject and predicate should be provided for the main resulting statement.
+For example, when writing a value for some control,
+the subject might identify the device,
+and the predicate the parameter:
+
+.. code-block:: c
+
+ SerdModel* model = my_model();
+ LV2_URID subject = urid_map("http://example.org/amp");
+ LV2_URID predicate = urid_map("http://example.org/gain");
+ const SerdSink* sink = serd_inserter_new(model, NULL);
+
+ const float value = 42.0f;
+
+ sratom_dump(dumper,
+ env,
+ sink,
+ subject,
+ predicate,
+ urid_map(LV2_ATOM__Float),
+ sizeof(float),
+ &value,
+ 0);
+
+Which would produce output like:
+
+.. code-block:: text
+
+ eg:amp eg:gain 42.0 .
+
+More complex atoms might produce several statements,
+for example an object may itself have several properties:
+
+.. code-block:: text
+
+ eg:mixer eg:pan [
+ eg:left 1.0 ;
+ eg:front 0.5 ;
+ ] .
+
+Representation
+==============
+
+If no subject and predicate are given,
+either explicitly with :func:`sratom_dump` or by using :func:`sratom_to_string`,
+then the atom will be written as the subject.
+Literals (which are not enough to form a statement) are written as the sole element of a list.
+This ensures that the representation can be transmitted, stored, or transformed without loss.
+For example, here is the terse string format (which is Turtle) of various atom types:
+
+.. code-block:: turtle
+
+ ( "hello" ) .
+
+ ( true ) .
+
+ ( 1 ) .
+
+ ( 3.0 ) .
+
+ ( <file:///absolute/path> ) .
+
+ ( <relative/path> ) .
+
+ ( eg:thing ) .
+
+ []
+ a atom:Tuple ;
+ rdf:value ( "foo" true ) .
+
+ []
+ a atom:Vector ;
+ atom:childType atom:Int ;
+ rdf:value ( 1 2 3 4 5 ) .
+
+ []
+ a atom:Sequence ;
+ rdf:value (
+ [
+ atom:frameTime 1 ;
+ rdf:value "901A01"^^midi:MidiEvent
+ ]
+ [
+ atom:frameTime 3 ;
+ rdf:value "902B02"^^midi:MidiEvent
+ ]
+ ) .
+
+Cleaning Up
+===========
+
+When finished, a dumper must be destroyed by :func:`sratom_dumper_free`:
+
+.. code-block:: c
+
+ sratom_dumper_free(dumper);
+
+Any newly-allocated strings returned by :func:`sratom_to_string` are independent,
+and may outlive the dumper that created them.
+These must be individually destroyed with :func:`sratom_free`.
+
+*************
+Loading Atoms
+*************
+
+:struct:`SratomLoader` can construct atoms from descriptions written by a dumper.
+This is typically used to load saved atoms from a file, socket, or data model.
+A new loader can be allocated with :func:`sratom_loader_new`:
+
+.. code-block:: c
+
+ SerdWorld* world = my_world();
+ LV2_URID_Map* map = my_urid_map();
+ SratomLoader* loader = sratom_loader_new(world, map);
+
+Once a loader is allocated it can be used to read any number of atoms.
+
+Loading Strings
+===============
+
+:func:`sratom_from_string` can be used to load atoms from strings created by :func:`sratom_to_string`:
+
+.. code-block:: c
+
+ const char* string = "( 42.0 ) .";
+
+ LV2_Atom* atom = sratom_from_string(loader, env, string);
+
+ do_something_with(atom);
+
+The environment should match the one used when dumping the string,
+so that namespace prefixes can be parsed correctly.
+The returned atom is newly allocated and owned by the caller,
+who must eventually destroy it with :func:`sratom_free`:
+
+.. code-block:: c
+
+ sratom_free(atom);
+
+Loading from a Model
+====================
+
+:func:`sratom_from_model` and the lower-level :func:`sratom_load` can be used to load atoms from a data model.
+A model contains statements,
+so this can be used to load atoms that were saved with :func:`sratom_dump`.
+The node that represents the atom must be given to specify where in the model to find the atom.
+Typically,
+this is the object of a statement with the subject and predicate passed to :func:`sratom_dump`.
+
+For example,
+given some model and node in an application,
+a new atom can be allocated from its representation in the model:
+
+.. code-block:: c
+
+ const SerdModel* model = my_model();
+ const SerdNode* value_node = get_value(model);
+
+ Atom* atom = sratom_from_model(loader,
+ base,
+ model,
+ value_node);
+
+The lower-level :func:`sratom_load` can be used with a :struct:`LV2_Atom_Forge` instead,
+which allows writing the atom directly to an existing buffer:
+
+.. code-block:: c
+
+ LV2_Atom_Forge* forge = my_buffer_writing_forge();
+
+ sratom_load(loader,
+ base,
+ forge,
+ model,
+ value_node);
+
+Cleaning Up
+===========
+
+When finished, a loader must be destroyed by :func:`sratom_loader_free`:
+
+.. code-block:: c
+
+ sratom_loader_free(loader);
+
+Any newly-allocated atoms returned by :func:`sratom_from_model` are independent,
+and may outlive the loader that created them.
+These must be individually destroyed with :func:`sratom_free`.
diff --git a/doc/c/xml/meson.build b/doc/c/xml/meson.build
index fdb55cc..42fbd93 100644
--- a/doc/c/xml/meson.build
+++ b/doc/c/xml/meson.build
@@ -1,9 +1,9 @@
doxygen = find_program('doxygen')
c_doxygen_input = []
-foreach h : c_headers
- c_doxygen_input += ['..' / h]
-endforeach
+# foreach h : sratom_c_headers
+# c_doxygen_input += ['..' / h]
+# endforeach
config = configuration_data()
config.set('SRATOM_SRCDIR', sratom_src_root)
@@ -15,5 +15,5 @@ c_doxyfile = configure_file(configuration: config,
c_index_xml = custom_target('sratom-c-index.xml',
command: [doxygen, '@INPUT0@'],
- input: [c_doxyfile] + c_header_files,
+ input: [c_doxyfile] + sratom_c_header_files,
output: 'index.xml')
diff --git a/doc/meson.build b/doc/meson.build
index 81457b9..e9f7749 100644
--- a/doc/meson.build
+++ b/doc/meson.build
@@ -10,7 +10,7 @@ if build_docs
subdir('c')
endif
-if meson.version().version_compare('>=0.53.0')
+if not meson.is_subproject() and meson.version().version_compare('>=0.53.0')
summary('Documentation', build_docs, bool_yn: true)
endif
diff --git a/meson.build b/meson.build
index c85b966..57498a2 100644
--- a/meson.build
+++ b/meson.build
@@ -53,6 +53,9 @@ if get_option('strict')
'-Wno-suggest-attribute=pure',
'-Wno-unsuffixed-float-constants',
'-Wno-unused-const-variable',
+
+ # FIXME: Just for tests
+ '-Wno-parentheses',
]
elif cc.get_id() == 'msvc'
c_warnings += [
@@ -84,8 +87,8 @@ if cc.get_id() == 'msvc'
add_project_arguments(msvc_args, language: ['c'])
endif
-c_headers = ['include/sratom/sratom.h']
-c_header_files = files(c_headers)
+sratom_c_headers = ['include/sratom/sratom.h']
+sratom_c_header_files = files(sratom_c_headers)
sources = [
'src/dumper.c',
@@ -150,7 +153,7 @@ pkg.generate(
description: 'A library for serializing LV2 atoms')
# Install header to a versioned include directory
-install_headers(c_headers, subdir: versioned_name / 'sratom')
+install_headers(sratom_c_header_files, subdir: versioned_name / 'sratom')
if not get_option('docs').disabled()
subdir('doc')
@@ -165,7 +168,7 @@ if is_variable('cpp')
subdir('bindings/cpp')
endif
-if meson.version().version_compare('>=0.53.0')
+if not meson.is_subproject() and meson.version().version_compare('>=0.53.0')
summary('Tests', get_option('tests'), bool_yn: true)
summary('Install prefix', get_option('prefix'))