mom.texi
4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
@c This is part of the GNU Mailutils manual.
@c Copyright (C) 1999,2000,2001,2002,2003,2004,
@c 2007,2008 Free Software Foundation, Inc.
@c See file mailutils.texi for copying conditions.
@comment *******************************************************************
@chapter Mailutils Object Model
Mailutils is written in C, the language is widely supported on
many platforms and the ABI (Binary Interface) for linking objects
with other languages (like Guile, Java, ...) is well-defined.
The C language does not provide support for object oriented programming,
but by using structures and pointers to function, it is possible to provide
a simple framework.
Every Mailutils object has a corresponding C structure holding its interface
and specific data. For example mu_object_t, is the root object and all mailutils objects
extends it:
@smallexample
struct _mu_object;
typedef struct _mu_object* mu_object_t;
/* Definition of the interface for mu_object */
struct _mu_object_vtable
@{
int (*create) (mu_object_t *object);
void (*destroy) (mu_object_t *object);
void (*notify) (mu_object_t object, int event, void *data);
@}
struct _mu_object
@{
struct _mu_object_vtable *vtable;
int type;
@}
@end smallexample
The @var{vtable} is an array of pointers to function, it provides the interface
or the list of function for this object. The library provides wrapper to
access the functions instead using the @var{vtable} directly.
@smallexample
int mu_object_notify(mu_object object, int event, void *data)
@{
if (object == NULL || object->vtable == NULL
|| object->vtable->notify == NULL)
return MU_ERR_NOT_SUPPORTED;
return object->vtable->notify (object, event, data);
@}
@end smallexample
Instead of using macros or the vtable directly.
@smallexample
#define mu_object_notify(o, evt, d) ((o)->vtable->notify(o, evt, d))
@end smallexample
@section Implementing an Interface
@comment ***********************************************************
@comment This is not a very good/useful example, we should do one using
@comment header or message, something usefully that would clarify the concepts
@comment better and at the same could be reuse in code by clients.
@comment
@comment For example mime_t "extends" message_t, this is a good example
@comment since you can consider a mime_t as a message_t but with extra functions.
@comment ***********************************************************
For a more concrete implementation, lets say we are implementing some caching mailbox
but we need to keep a better track of the objects in our implementation.
We take the approach of simple reference counting and extend the mu_object_t.
@smallexample
#include <mailutils/sys/object.h>
struct my_object;
typedef struct refcount* refcount;
struct refcount_vtable
@{
struct _mu_object_vtable base;
int (*increment)(refcount_t);
int (*decrement)(refcount_t);
@}
struct refcount
@{
struct refcount_vtable * vtable;
int count;
@}
static int
refcount_increment (mu_object_t obj)
@{
refcount_t refcount = (refcount_t)obj;
refcount->count++;
return refcount->count;
@}
static int
refcount_decrement (mu_object_t obj)
@{
refcount_t refcount = (refcount_t)obj;
if (refcount->count > 0)
refcount->count--;
return refcount->count;
@}
int
my_mu_object_create (mu_object_t *pobject)
@{
static struct refcount_vtable* vtable;
refcount_t ref;
if (object == NULL)
return EINVAL;
if (!vtable)
@{
vtable = calloc(1, sizeof(*vtable));
if (vtable == NULL)
return ENOMEM;
vtable->base.vtable = &_mu_object_vtable; // FIXME where can they get the base vtable
vtable->increment = refcount_increment;
vtable->decrement = refcount_decrement;
@}
ref = malloc(sizeof *ref);
ref->base = vtable;
*pobject = &ref->base.vtable
return 0;
@}
@end smallexample
The interface adds a @code{decrement} and @code{increment} to the @code{mu_object_t}
interface. Creating a @code{refcount_t} can be savely typecast to @code{mu_object_t},
for example:
@smallexample
refcount_t ref;
mu_object_t obj;
refcount_create (&ref);
/* send a notification to the listeners of an event. */
mu_object_notify ((mu_object_t)ref, 5, NULL)
@end smallexample