add opaque object example
Graham Ollis authored 1 year, 6 months ago
Graham✈️✈️ committed 1 year, 6 months ago
1110 | 1110 | returned to Perl as a reference to a scalar. Platypus also supports string |
1111 | 1111 | pointers (`string*`). (Though the C equivalent to a `string*` is a double |
1112 | 1112 | pointer to char `char**`). |
1113 | ||
1114 | ## Opaque Pointers (objects) | |
1115 | ||
1116 | ### C Source | |
1117 | ||
1118 | ``` | |
1119 | #include <string.h> | |
1120 | #include <stdlib.h> | |
1121 | ||
1122 | typedef struct person_t { | |
1123 | char *name; | |
1124 | unsigned int age; | |
1125 | } person_t; | |
1126 | ||
1127 | person_t * | |
1128 | person_new(const char *name, unsigned int age) { | |
1129 | person_t *self = malloc(sizeof(person_t)); | |
1130 | self->name = strdup(name); | |
1131 | self->age = age; | |
1132 | } | |
1133 | ||
1134 | const char * | |
1135 | person_name(person_t *self) { | |
1136 | return self->name; | |
1137 | } | |
1138 | ||
1139 | unsigned int | |
1140 | person_age(person_t *self) { | |
1141 | return self->age; | |
1142 | } | |
1143 | ||
1144 | void | |
1145 | person_free(person_t *self) { | |
1146 | free(self->name); | |
1147 | free(self); | |
1148 | } | |
1149 | ``` | |
1150 | ||
1151 | ### Perl Source | |
1152 | ||
1153 | ```perl | |
1154 | use FFI::Platypus 2.00; | |
1155 | ||
1156 | my $ffi = FFI::Platypus->new( | |
1157 | api => 2, | |
1158 | lib => './person.so', | |
1159 | ); | |
1160 | ||
1161 | $ffi->type( 'opaque' => 'person_t' ); | |
1162 | ||
1163 | $ffi->attach( person_new => ['string','unsigned int'] => 'person_t' ); | |
1164 | $ffi->attach( person_name => ['person_t'] => 'string' ); | |
1165 | $ffi->attach( person_age => ['person_t'] => 'unsigned int' ); | |
1166 | $ffi->attach( person_free => ['person_t'] ); | |
1167 | ||
1168 | my $person = person_new( 'Roger Frooble Bits', 35 ); | |
1169 | ||
1170 | print "name = ", person_name($person), "\n"; | |
1171 | print "age = ", person_age($person), "\n"; | |
1172 | ||
1173 | person_free($person); | |
1174 | ``` | |
1175 | ||
1176 | ### Execute | |
1177 | ||
1178 | ``` | |
1179 | $ gcc -shared -o person.so person.c | |
1180 | $ perl person.pl | |
1181 | name = Roger Frooble Bits | |
1182 | age = 35 | |
1183 | ``` | |
1184 | ||
1185 | ### Discussion | |
1186 | ||
1187 | An opaque pointer is a pointer (memory address) that is pointing to _something_ | |
1188 | but you do not know the structure of that something. In C this is usually a | |
1189 | `void*`, but it could also be a pointer to a `struct` without a defined body. | |
1190 | ||
1191 | This is often used to as an abstraction around objects in C. Here in the C | |
1192 | code we have a `person_t` struct with functions to create (a constructor), free | |
1193 | (a destructor) and query it (methods). | |
1194 | ||
1195 | The Perl code can then use the constructor, methods and destructors without having | |
1196 | to understand the internals. The `person_t` internals can also be changed | |
1197 | without having to modify the calling code. | |
1198 | ||
1199 | We use the Platypus [type method](#type) to create an alias of `opaque` called | |
1200 | `person_t`. While this is not necessary, it does make the Perl code easier | |
1201 | to understand. | |
1202 | ||
1203 | In later examples we will see how to hide the use of `opaque` types further | |
1204 | using the `object` type, but for some code direct use of `opaque` is | |
1205 | appropriate. | |
1113 | 1206 | |
1114 | 1207 | ## Arrays |
1115 | 1208 |
0 | #include <string.h> | |
1 | #include <stdlib.h> | |
2 | ||
3 | typedef struct person_t { | |
4 | char *name; | |
5 | unsigned int age; | |
6 | } person_t; | |
7 | ||
8 | person_t * | |
9 | person_new(const char *name, unsigned int age) { | |
10 | person_t *self = malloc(sizeof(person_t)); | |
11 | self->name = strdup(name); | |
12 | self->age = age; | |
13 | } | |
14 | ||
15 | const char * | |
16 | person_name(person_t *self) { | |
17 | return self->name; | |
18 | } | |
19 | ||
20 | unsigned int | |
21 | person_age(person_t *self) { | |
22 | return self->age; | |
23 | } | |
24 | ||
25 | void | |
26 | person_free(person_t *self) { | |
27 | free(self->name); | |
28 | free(self); | |
29 | } |
0 | use strict; | |
1 | use warnings; | |
2 | use FFI::Platypus 2.00; | |
3 | ||
4 | my $ffi = FFI::Platypus->new( | |
5 | api => 2, | |
6 | lib => './person.so', | |
7 | ); | |
8 | ||
9 | $ffi->type( 'opaque' => 'person_t' ); | |
10 | ||
11 | $ffi->attach( person_new => ['string','unsigned int'] => 'person_t' ); | |
12 | $ffi->attach( person_name => ['person_t'] => 'string' ); | |
13 | $ffi->attach( person_age => ['person_t'] => 'unsigned int' ); | |
14 | $ffi->attach( person_free => ['person_t'] ); | |
15 | ||
16 | my $person = person_new( 'Roger Frooble Bits', 35 ); | |
17 | ||
18 | print "name = ", person_name($person), "\n"; | |
19 | print "age = ", person_age($person), "\n"; | |
20 | ||
21 | person_free($person); |
1513 | 1513 | pointers (C<string*>). (Though the C equivalent to a C<string*> is a double |
1514 | 1514 | pointer to char C<char**>). |
1515 | 1515 | |
1516 | =head2 Opaque Pointers (objects) | |
1517 | ||
1518 | =head3 C Source | |
1519 | ||
1520 | # EXAMPLE: examples/person.c | |
1521 | ||
1522 | =head3 Perl Source | |
1523 | ||
1524 | # EXAMPLE: examples/person.pl | |
1525 | ||
1526 | =head3 Execute | |
1527 | ||
1528 | $ gcc -shared -o person.so person.c | |
1529 | $ perl person.pl | |
1530 | name = Roger Frooble Bits | |
1531 | age = 35 | |
1532 | ||
1533 | =head3 Discussion | |
1534 | ||
1535 | An opaque pointer is a pointer (memory address) that is pointing to I<something> | |
1536 | but you do not know the structure of that something. In C this is usually a | |
1537 | C<void*>, but it could also be a pointer to a C<struct> without a defined body. | |
1538 | ||
1539 | This is often used to as an abstraction around objects in C. Here in the C | |
1540 | code we have a C<person_t> struct with functions to create (a constructor), free | |
1541 | (a destructor) and query it (methods). | |
1542 | ||
1543 | The Perl code can then use the constructor, methods and destructors without having | |
1544 | to understand the internals. The C<person_t> internals can also be changed | |
1545 | without having to modify the calling code. | |
1546 | ||
1547 | We use the Platypus L<type method|/type> to create an alias of C<opaque> called | |
1548 | C<person_t>. While this is not necessary, it does make the Perl code easier | |
1549 | to understand. | |
1550 | ||
1551 | In later examples we will see how to hide the use of C<opaque> types further | |
1552 | using the C<object> type, but for some code direct use of C<opaque> is | |
1553 | appropriate. | |
1554 | ||
1516 | 1555 | =head2 Arrays |
1517 | 1556 | |
1518 | 1557 | =head3 C Source |