def _validate(self): if self._decoder is None: from bdec.decode import Decoder self._decoder = Decoder(self)
class Entry(object): """An entry is an item in a protocol that can be decoded. This class designed to be derived by other classes (not instantiated directly). """ def __init__(self, name, length, children, constraints=[]): """Construct an Entry instance. children -- A list of Entry or Child instances. length -- Optionally specify the size in bits of the entry. Must be an instance of bdec.expression.Expression or an integer. constraints -- A list of constraints for the value of this entry. """ if length is not None: if isinstance(length, int): length = Constant(length) assert isinstance(length, Expression) self.name = name self.length = length self._children = () self.children = children self._decoder = None self._encoder = None self.constraints = list(constraints) for constraint in self.constraints: assert getattr(constraint, 'check') is not None def _get_children(self): return self._children def _set_children(self, children): from bdec.spec.references import ReferencedEntry items = [] for child in children: if isinstance(child, Child): items.append(child) else: items.append(Child(child.name, child)) if isinstance(items[-1].entry, ReferencedEntry): items[-1].entry.add_parent(items[-1]) self._children = list(items) children = property(_get_children, _set_children) def _validate(self): if self._decoder is None: from bdec.decode import Decoder self._decoder = Decoder(self) def decode(self, data, context={}, name=None): """ Shortcut to bdec.decode.Decoder(self) """ self._validate() return self._decoder.decode(data, context, name) def encode(self, query, value): if self._encoder is None: from bdec.encode import create_encoder self._encoder = create_encoder(self) value = self._encoder.get_value(query, value, 0, self.name, {}) return self._encoder.encode(query, value, 0, {}, self.name) def is_hidden(self): """Is this a 'hidden' entry.""" return is_hidden(self.name) def __str__(self): return "%s '%s'" % (self.__class__.__name__.lower(), self.name) def __repr__(self): return "%s '%s'" % (self.__class__, self.name) def _range(self, ignore_entries): """ Can be implemented by derived classes to detect ranges. """ return bdec.entry.Range() def range(self, ignore_entries=set()): """Return a Range instance indicating the length of this entry. ignore_entries -- If self is in ignore_entries, a default Range instance will be returned. 'self' and all child entries will be added to ignore_entries. """ if self in ignore_entries: # If an entry is recursive, we cannot predict how long it will be. return Range() result = None if self.length is not None: try: min = max = self.length.evaluate({}) result = bdec.entry.Range(min, max) except UndecodedReferenceError: pass if result is None: ignore_entries.add(self) result = self._range(ignore_entries) ignore_entries.remove(self) return result