Commit eb95554e eb95554ec9834701d7d9c41355e67fb322938a40 by Alain Magloire

Draft explanation of the MOM(Mailutils Object Model)

1 parent da9bd682
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