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