+class compound(object):
+ def __init__(self, *parts):
+ self.parts = parts
+
+ small = object()
+ large = object()
+ def minim(self, *parts):
+ return parts + tuple([self.small] * (len(self.parts) - len(parts)))
+ def maxim(self, *parts):
+ return parts + tuple([self.large] * (len(self.parts) - len(parts)))
+
+ def encode(self, obs):
+ if len(obs) != len(self.parts):
+ raise ValueError("invalid length of compound data: " + str(len(obs)) + ", rather than " + len(self.parts))
+ buf = bytearray()
+ for ob, part in zip(obs, self.parts):
+ if ob is self.small:
+ buf.append(0x01)
+ elif ob is self.large:
+ buf.append(0x02)
+ else:
+ dat = part.encode(ob)
+ if len(dat) < 128:
+ buf.append(0x80 | len(dat))
+ buf.extend(dat)
+ else:
+ buf.extend(struct.pack(">BI", 0, len(dat)))
+ buf.extend(dat)
+ return bytes(buf)
+ def decode(self, dat):
+ ret = []
+ off = 0
+ for part in self.parts:
+ fl = dat[off]
+ off += 1
+ if fl & 0x80:
+ ln = fl & 0x7f
+ elif fl == 0x01:
+ ret.append(self.small)
+ continue
+ elif fl == 0x02:
+ ret.append(self.large)
+ continue
+ else:
+ ln = struct.unpack(">I", dat[off:off + 4])[0]
+ off += 4
+ ret.append(part.decode(dat[off:off + ln]))
+ off += ln
+ return tuple(ret)
+ def compare(self, al, bl):
+ if (len(al) != len(self.parts)) or (len(bl) != len(self.parts)):
+ raise ValueError("invalid length of compound data: " + str(len(al)) + ", " + str(len(bl)) + ", rather than " + len(self.parts))
+ for a, b, part in zip(al, bl, self.parts):
+ if a in (self.small, self.large) or b in (self.small, self.large):
+ if a is b:
+ return 0
+ if a is self.small:
+ return -1
+ elif b is self.small:
+ return 1
+ elif a is self.large:
+ return 1
+ elif b is self.large:
+ return -1
+ c = part.compare(a, b)
+ if c != 0:
+ return c
+ return 0
+
+def floatcmp(a, b):
+ if math.isnan(a) and math.isnan(b):
+ return 0
+ elif math.isnan(a):
+ return -1
+ elif math.isnan(b):
+ return 1
+ elif a < b:
+ return -1
+ elif a > b:
+ return 1
+ else:
+ return 0
+
+t_bool = simpletype((lambda ob: b"\x01" if ob else b"\x00"), (lambda dat: False if dat == b"x\00" else True))
+t_int = simpletype.struct(">q")
+t_uint = simpletype.struct(">Q")
+t_dbid = t_uint
+t_float = simpletype.struct(">d")
+t_float.compare = floatcmp
+t_str = simpletype((lambda ob: ob.encode("utf-8")), (lambda dat: dat.decode("utf-8")))
+t_casestr = foldtype((lambda ob: ob.encode("utf-8")), (lambda dat: dat.decode("utf-8")),
+ (lambda st: st.lower()))