wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

messages.py (2198B)


      1 from pyxp.fields import *
      2 
      3 class MessageBase(type):
      4     idx = 0
      5 
      6     def __new__(cls, name, bases, attrs):
      7         fields = []
      8         fieldmap = {}
      9         for k, v in attrs.items():
     10             if isinstance(v, Field):
     11                 attrs[k] = None
     12                 fields.append(v)
     13                 fieldmap[k] = v
     14                 v.name = k
     15         fields.sort(lambda a, b: cmp(a.id, b.id))
     16 
     17         new_cls = super(MessageBase, cls).__new__(cls, name, bases, attrs)
     18 
     19         map = getattr(new_cls, 'fieldmap', {})
     20         map.update(fieldmap)
     21         new_cls.fields = getattr(new_cls, 'fields', ()) + tuple(fields)
     22         new_cls.fieldmap = map
     23         for f in fields:
     24             f.message = new_cls
     25         return new_cls
     26 
     27 class Message(object):
     28     __metaclass__ = MessageBase
     29     def __init__(self, *args, **kwargs):
     30         if args:
     31             args = dict(zip((f.name for f in self.fields), args))
     32             args.update(kwargs)
     33             kwargs = args;
     34         for k, v in kwargs.iteritems():
     35             assert k in self.fieldmap, "Invalid keyword argument"
     36             setattr(self, k, v)
     37 
     38     @classmethod
     39     def field(cls):
     40         class MessageField(Field):
     41             def repr(self):
     42                 return cls.__name__
     43             def unmarshall(self, data, offset):
     44                 return cls.unmarshall(data, offset)
     45             def marshall(self, val):
     46                 return val.marshall()
     47         return MessageField()
     48 
     49     @classmethod
     50     def unmarshall(cls, data, offset=0):
     51         vals = {}
     52         start = offset
     53         for field in cls.fields:
     54             size, vals[field.name] = field.unmarshall(data, offset)
     55             offset += size
     56         return offset - start, cls(**vals)
     57     def marshall(self):
     58         res = []
     59         callbacks = []
     60         for field in self.fields:
     61             val = field.marshall(getattr(self, field.name, None))
     62             if callable(val):
     63                 callbacks.append((val, len(res)))
     64             if isinstance(val, list):
     65                 res += val
     66             else:
     67                 res.append(val)
     68         for fn, i in reversed(callbacks):
     69             res[i] = fn(res, i)
     70         return res
     71 
     72 # vim:se sts=4 sw=4 et: