OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """The meta classes used by the mojo python bindings.""" | 5 """The metaclasses used by the mojo python bindings.""" |
6 | 6 |
7 class MojoEnumType(type): | 7 class MojoEnumType(type): |
8 """Meta class for enumerations. | 8 """Meta class for enumerations. |
9 | 9 |
10 Usage: | 10 Usage: |
11 class MyEnum(object): | 11 class MyEnum(object): |
12 __metaclass__ = MojoEnumType | 12 __metaclass__ = MojoEnumType |
13 VALUES = [ | 13 VALUES = [ |
14 ('A', 0), | 14 ('A', 0), |
15 'B', | 15 'B', |
16 ('C', 5), | 16 ('C', 5), |
17 ] | 17 ] |
18 | 18 |
19 This will define a enum with 3 values, A = 0, B = 1 and C = 5. | 19 This will define a enum with 3 values, 'A' = 0, 'B' = 1 and 'C' = 5. |
20 """ | 20 """ |
21 | 21 |
22 def __new__(mcs, name, bases, dictionary): | 22 def __new__(mcs, name, bases, dictionary): |
23 class_members = { | 23 dictionary['__slots__'] = () |
24 '__new__': None, | 24 dictionary['__new__'] = None |
25 } | |
26 for value in dictionary.pop('VALUES', []): | 25 for value in dictionary.pop('VALUES', []): |
27 if not isinstance(value, tuple): | 26 if not isinstance(value, tuple): |
28 raise ValueError('incorrect value: %r' % value) | 27 raise ValueError('incorrect value: %r' % value) |
29 key, enum_value = value | 28 key, enum_value = value |
30 if isinstance(key, str) and isinstance(enum_value, int): | 29 if isinstance(key, str) and isinstance(enum_value, int): |
31 class_members[key] = enum_value | 30 dictionary[key] = enum_value |
32 else: | 31 else: |
33 raise ValueError('incorrect value: %r' % value) | 32 raise ValueError('incorrect value: %r' % value) |
34 return type.__new__(mcs, name, bases, class_members) | 33 return type.__new__(mcs, name, bases, dictionary) |
35 | 34 |
36 def __setattr__(mcs, key, value): | 35 def __setattr__(mcs, key, value): |
37 raise AttributeError, 'can\'t set attribute' | 36 raise AttributeError, 'can\'t set attribute' |
38 | 37 |
39 def __delattr__(mcs, key): | 38 def __delattr__(mcs, key): |
40 raise AttributeError, 'can\'t delete attribute' | 39 raise AttributeError, 'can\'t delete attribute' |
41 | 40 |
42 | 41 |
43 class MojoStructType(type): | 42 class MojoStructType(type): |
44 """Meta class for structs. | 43 """Meta class for structs. |
45 | 44 |
46 Usage: | 45 Usage: |
47 class MyStruct(object): | 46 class MyStruct(object): |
48 __metaclass__ = MojoStructType | 47 __metaclass__ = MojoStructType |
49 DESCRIPTOR = { | 48 DESCRIPTOR = { |
50 'constants': { | 49 'constants': { |
51 'C1': 1, | 50 'C1': 1, |
52 'C2': 2, | 51 'C2': 2, |
53 }, | 52 }, |
54 'enums': { | 53 'enums': { |
55 'ENUM1': [ | 54 'ENUM1': [ |
56 ('V1', 1), | 55 ('V1', 1), |
57 'V2', | 56 'V2', |
58 ], | 57 ], |
59 'ENUM2': [ | 58 'ENUM2': [ |
60 ('V1', 1), | 59 ('V1', 1), |
61 'V2', | 60 'V2', |
62 ], | 61 ], |
63 }, | 62 }, |
| 63 'fields': [ |
| 64 FieldDescriptor('x', _descriptor.TYPE_INT32, 0), |
| 65 ], |
64 } | 66 } |
65 | 67 |
66 This will define an struct, with 2 constants C1 and C2, and 2 enums ENUM1 | 68 This will define an struct, with: |
67 and ENUM2, each of those having 2 values, V1 and V2. | 69 - 2 constants 'C1' and 'C2'; |
| 70 - 2 enums 'ENUM1' and 'ENUM2', each of those having 2 values, 'V1' and |
| 71 'V2'; |
| 72 - 1 int32 field named 'x'. |
68 """ | 73 """ |
69 | 74 |
70 def __new__(mcs, name, bases, dictionary): | 75 def __new__(mcs, name, bases, dictionary): |
71 class_members = { | 76 dictionary['__slots__'] = ('_fields') |
72 '__slots__': [], | |
73 } | |
74 descriptor = dictionary.pop('DESCRIPTOR', {}) | 77 descriptor = dictionary.pop('DESCRIPTOR', {}) |
75 | 78 |
76 # Add constants | 79 # Add constants |
77 class_members.update(descriptor.get('constants', {})) | 80 dictionary.update(descriptor.get('constants', {})) |
78 | 81 |
79 # Add enums | 82 # Add enums |
80 enums = descriptor.get('enums', {}) | 83 enums = descriptor.get('enums', {}) |
81 for key in enums: | 84 for key in enums: |
82 class_members[key] = MojoEnumType(key, | 85 dictionary[key] = MojoEnumType(key, (object,), { 'VALUES': enums[key] }) |
83 (object,), | |
84 { 'VALUES': enums[key] }) | |
85 | 86 |
86 return type.__new__(mcs, name, bases, class_members) | 87 # Add fields |
| 88 for field in descriptor.get('fields', []): |
| 89 dictionary[field.name] = _BuildProperty(field) |
87 | 90 |
| 91 # Add init |
| 92 dictionary['__init__'] = _StructInit |
| 93 |
| 94 return type.__new__(mcs, name, bases, dictionary) |
| 95 |
| 96 # Prevent adding new attributes, or mutating constants. |
88 def __setattr__(mcs, key, value): | 97 def __setattr__(mcs, key, value): |
89 raise AttributeError, 'can\'t set attribute' | 98 raise AttributeError, 'can\'t set attribute' |
90 | 99 |
| 100 # Prevent deleting constants. |
91 def __delattr__(mcs, key): | 101 def __delattr__(mcs, key): |
92 raise AttributeError, 'can\'t delete attribute' | 102 raise AttributeError, 'can\'t delete attribute' |
| 103 |
| 104 |
| 105 def _StructInit(self, **kwargs): |
| 106 self._fields = {} |
| 107 for name in kwargs: |
| 108 self.__setattr__(name, kwargs[name]) |
| 109 |
| 110 |
| 111 def _BuildProperty(field): |
| 112 """Build the property for the given field.""" |
| 113 |
| 114 # pylint: disable=W0212 |
| 115 def Get(self): |
| 116 if field.name not in self._fields: |
| 117 self._fields[field.name] = field.GetDefaultValue() |
| 118 return self._fields[field.name] |
| 119 |
| 120 # pylint: disable=W0212 |
| 121 def Set(self, value): |
| 122 self._fields[field.name] = field.field_type.Convert(value) |
| 123 |
| 124 return property(Get, Set) |
OLD | NEW |