Introduction
The whole API will be GObject-based, which gives us a nice signal and property system, subclassing, and easy binding to several languages through existing binding systems.
Object design
The main object of focus will be SoylentPerson?. SoylentPerson? is a first-class object, providing an abstract interface to whatever backend is in use. More on this later.
Rather than reinventing several wheels, the GObject property system and signal system will be heavily used in SoylentPerson?. Each property of a person will be a GObject property. This allows for any program that can introspect any GObject to get all the data about SoylentPerson? and lets us overcome several issues, such as needing to re-implement marshalling.
Property generation
As a lot of code is needed for each property, the whole property support will be auto-generated from a perl script based on a data file. The current format of that file that I have looks like this:
name {
type: SoylentName *
}
nickname {
type: string
}
emails {
type: collection
subtype: string
}
phones {
type: collection
subtype: string
}
ims {
type: collection
subtype: GalagoAccount *
}
And so on.
This file will be transformed into a .c and .h file that will be compiled into the library. The type and subtype fields have some magic values (string, boolean, integer, and collection). Anything unrecognized is passed through (e.g., GalagoAccount *) and is assumed to be a valid type.
Properties will be able to be marked as read-only. Otherwise, the read-only/read-write state of the property will be dependent on the backend. If a property is marked read-write in SoylentPerson?, but the backend only supports read-only, the read-only state takes precedence. That is, both SoylentPerson? and the backend must both specify read-write for it to be read-write, otherwise it will be read-only.
The standard data types (string, integer, boolean) are fairly self-explanatory. However, there is a special type called 'collection' that should be described.
Collections
The collection data type represents a collection of data of type 'subtype.' This can be a collection of strings, a collection of structs, etc. In code, this will be represented by a SoylentCollection? object. A SoylentCollection? object maintains a list of key, value pairs. The key is a human-readable label for the value, and the value is of whatever type the collection holds. A list of pairs can be retrieved from a collection, as can a list of labels (keys) or list of values.
Signals can be attached to a collection to notify on any additions, removals, or changes.
Many types of data will live in a collection. IM accounts, phone numbers, and e-mails, to name a few.
Accessing Properties
Properties can be accessed the standard GObject way. For example:
SoylentName *name;
SoylentCollection *phones;
char *nickname;
g_object_get(G_OBJECT(person),
"name", &name,
"phones", &phones,
"nickname", &nickname,
NULL);
g_free(nickname);
g_object_unref(name);
g_object_unref(phones);
or:
SoylentName *name = g_object_get_data(G_OBJECT(person), "name");
It's a fairly easy, standard API, with notifications on properties. However, this could also be wrapped a bit more, in two ways (both of which can be used). The first is a set of type-specific generic API functions, such as:
SoylentName *name = soylent_person_get_struct(person, "name"); const char *soylent_person_get_string(person, "nickname");
and:
SoylentName *name = soylent_person_get_name(person); const char *soylent_person_get_nickname(person);
The specific set of functions could be automatically created by the generator script.
Property names won't actually have to be specified as literal strings. The generator script will generate a set of #defines to map a constant name to the literal string.
