##// END OF EJS Templates
commit: factor out empty commit check to `basectx.isempty()`...
commit: factor out empty commit check to `basectx.isempty()` This enables reuse in other places, e.g. those dealing with `memctx`. Differential Revision: https://phab.mercurial-scm.org/D8729

File last commit:

r44440:c8a51a90 default
r45648:3e40abe0 default
Show More
pybser.py
575 lines | 18.0 KiB | text/x-python | PythonLexer
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 # Copyright 2015 Facebook, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name Facebook nor the names of its contributors may be used to
# endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 # no unicode literals
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 from __future__ import absolute_import, division, print_function
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656
import binascii
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 import collections
import ctypes
import struct
import sys
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 from . import compat
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 BSER_ARRAY = b"\x00"
BSER_OBJECT = b"\x01"
BSER_BYTESTRING = b"\x02"
BSER_INT8 = b"\x03"
BSER_INT16 = b"\x04"
BSER_INT32 = b"\x05"
BSER_INT64 = b"\x06"
BSER_REAL = b"\x07"
BSER_TRUE = b"\x08"
BSER_FALSE = b"\x09"
BSER_NULL = b"\x0a"
BSER_TEMPLATE = b"\x0b"
BSER_SKIP = b"\x0c"
BSER_UTF8STRING = b"\x0d"
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656
if compat.PYTHON3:
STRING_TYPES = (str, bytes)
unicode = str
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def tobytes(i):
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 return str(i).encode("ascii")
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 long = int
else:
STRING_TYPES = (unicode, str)
tobytes = bytes
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
# Leave room for the serialization header, which includes
# our overall length. To make things simpler, we'll use an
# int32 for the header
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00"
EMPTY_HEADER_V2 = b"\x00\x02\x00\x00\x00\x00\x05\x00\x00\x00\x00"
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 def _int_size(x):
"""Return the smallest size int that can store the value"""
if -0x80 <= x <= 0x7F:
return 1
elif -0x8000 <= x <= 0x7FFF:
return 2
elif -0x80000000 <= x <= 0x7FFFFFFF:
return 4
elif long(-0x8000000000000000) <= x <= long(0x7FFFFFFFFFFFFFFF):
return 8
else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise RuntimeError("Cannot represent value: " + str(x))
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def _buf_pos(buf, pos):
ret = buf[pos]
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 # Normalize the return type to bytes
if compat.PYTHON3 and not isinstance(ret, bytes):
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 ret = bytes((ret,))
return ret
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 class _bser_buffer(object):
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def __init__(self, version):
self.bser_version = version
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.buf = ctypes.create_string_buffer(8192)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 if self.bser_version == 1:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
tobytes(len(EMPTY_HEADER)) + b"s", self.buf, 0, EMPTY_HEADER
)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 self.wpos = len(EMPTY_HEADER)
else:
assert self.bser_version == 2
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
tobytes(len(EMPTY_HEADER_V2)) + b"s",
self.buf,
0,
EMPTY_HEADER_V2,
)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 self.wpos = len(EMPTY_HEADER_V2)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
def ensure_size(self, size):
while ctypes.sizeof(self.buf) - self.wpos < size:
ctypes.resize(self.buf, ctypes.sizeof(self.buf) * 2)
def append_long(self, val):
size = _int_size(val)
to_write = size + 1
self.ensure_size(to_write)
if size == 1:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=cb", self.buf, self.wpos, BSER_INT8, val)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 2:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=ch", self.buf, self.wpos, BSER_INT16, val)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 4:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=ci", self.buf, self.wpos, BSER_INT32, val)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 8:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=cq", self.buf, self.wpos, BSER_INT64, val)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise RuntimeError("Cannot represent this long value")
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.wpos += to_write
def append_string(self, s):
if isinstance(s, unicode):
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 s = s.encode("utf-8")
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 s_len = len(s)
size = _int_size(s_len)
to_write = 2 + size + s_len
self.ensure_size(to_write)
if size == 1:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=ccb" + tobytes(s_len) + b"s",
self.buf,
self.wpos,
BSER_BYTESTRING,
BSER_INT8,
s_len,
s,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 2:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=cch" + tobytes(s_len) + b"s",
self.buf,
self.wpos,
BSER_BYTESTRING,
BSER_INT16,
s_len,
s,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 4:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=cci" + tobytes(s_len) + b"s",
self.buf,
self.wpos,
BSER_BYTESTRING,
BSER_INT32,
s_len,
s,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 8:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=ccq" + tobytes(s_len) + b"s",
self.buf,
self.wpos,
BSER_BYTESTRING,
BSER_INT64,
s_len,
s,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise RuntimeError("Cannot represent this string value")
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.wpos += to_write
def append_recursive(self, val):
if isinstance(val, bool):
needed = 1
self.ensure_size(needed)
if val:
to_encode = BSER_TRUE
else:
to_encode = BSER_FALSE
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=c", self.buf, self.wpos, to_encode)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.wpos += needed
elif val is None:
needed = 1
self.ensure_size(needed)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=c", self.buf, self.wpos, BSER_NULL)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.wpos += needed
elif isinstance(val, (int, long)):
self.append_long(val)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 elif isinstance(val, STRING_TYPES):
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.append_string(val)
elif isinstance(val, float):
needed = 9
self.ensure_size(needed)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=cd", self.buf, self.wpos, BSER_REAL, val)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.wpos += needed
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 elif isinstance(val, collections.Mapping) and isinstance(
val, collections.Sized
):
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 val_len = len(val)
size = _int_size(val_len)
needed = 2 + size
self.ensure_size(needed)
if size == 1:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=ccb",
self.buf,
self.wpos,
BSER_OBJECT,
BSER_INT8,
val_len,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 2:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=cch",
self.buf,
self.wpos,
BSER_OBJECT,
BSER_INT16,
val_len,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 4:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=cci",
self.buf,
self.wpos,
BSER_OBJECT,
BSER_INT32,
val_len,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 8:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=ccq",
self.buf,
self.wpos,
BSER_OBJECT,
BSER_INT64,
val_len,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise RuntimeError("Cannot represent this mapping value")
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.wpos += needed
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 if compat.PYTHON3:
iteritems = val.items()
else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 iteritems = val.iteritems() # noqa: B301 Checked version above
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 for k, v in iteritems:
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.append_string(k)
self.append_recursive(v)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 elif isinstance(val, collections.Iterable) and isinstance(
val, collections.Sized
):
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 val_len = len(val)
size = _int_size(val_len)
needed = 2 + size
self.ensure_size(needed)
if size == 1:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=ccb", self.buf, self.wpos, BSER_ARRAY, BSER_INT8, val_len
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 2:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=cch",
self.buf,
self.wpos,
BSER_ARRAY,
BSER_INT16,
val_len,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 4:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=cci",
self.buf,
self.wpos,
BSER_ARRAY,
BSER_INT32,
val_len,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 elif size == 8:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(
b"=ccq",
self.buf,
self.wpos,
BSER_ARRAY,
BSER_INT64,
val_len,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise RuntimeError("Cannot represent this sequence value")
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 self.wpos += needed
for v in val:
self.append_recursive(v)
else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise RuntimeError("Cannot represent unknown value type")
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def dumps(obj, version=1, capabilities=0):
bser_buf = _bser_buffer(version=version)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 bser_buf.append_recursive(obj)
# Now fill in the overall length
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 if version == 1:
obj_len = bser_buf.wpos - len(EMPTY_HEADER)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=i", bser_buf.buf, 3, obj_len)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 obj_len = bser_buf.wpos - len(EMPTY_HEADER_V2)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 struct.pack_into(b"=i", bser_buf.buf, 2, capabilities)
struct.pack_into(b"=i", bser_buf.buf, 7, obj_len)
return bser_buf.buf.raw[: bser_buf.wpos]
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
# This is a quack-alike with the bserObjectType in bser.c
# It provides by getattr accessors and getitem for both index
# and name.
class _BunserDict(object):
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 __slots__ = ("_keys", "_values")
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
def __init__(self, keys, values):
self._keys = keys
self._values = values
def __getattr__(self, name):
return self.__getitem__(name)
def __getitem__(self, key):
if isinstance(key, (int, long)):
return self._values[key]
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 elif key.startswith("st_"):
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 # hack^Wfeature to allow mercurial to use "st_size" to
# reference "size"
key = key[3:]
try:
return self._values[self._keys.index(key)]
Martin von Zweigbergk
cleanup: delete lots of unused local variables...
r41401 except ValueError:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise KeyError("_BunserDict has no key %s" % key)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
def __len__(self):
return len(self._keys)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 class Bunser(object):
def __init__(self, mutable=True, value_encoding=None, value_errors=None):
self.mutable = mutable
self.value_encoding = value_encoding
if value_encoding is None:
self.value_errors = None
elif value_errors is None:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 self.value_errors = "strict"
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 else:
self.value_errors = value_errors
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 @staticmethod
def unser_int(buf, pos):
try:
int_type = _buf_pos(buf, pos)
except IndexError:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise ValueError("Invalid bser int encoding, pos out of range")
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 if int_type == BSER_INT8:
needed = 2
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 fmt = b"=b"
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 elif int_type == BSER_INT16:
needed = 3
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 fmt = b"=h"
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 elif int_type == BSER_INT32:
needed = 5
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 fmt = b"=i"
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 elif int_type == BSER_INT64:
needed = 9
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 fmt = b"=q"
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise ValueError(
"Invalid bser int encoding 0x%s at position %s"
% (binascii.hexlify(int_type).decode("ascii"), pos)
)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 int_val = struct.unpack_from(fmt, buf, pos + 1)[0]
return (int_val, pos + needed)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def unser_utf8_string(self, buf, pos):
str_len, pos = self.unser_int(buf, pos + 1)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
return (str_val.decode("utf-8"), pos + str_len)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def unser_bytestring(self, buf, pos):
str_len, pos = self.unser_int(buf, pos + 1)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 if self.value_encoding is not None:
str_val = str_val.decode(self.value_encoding, self.value_errors)
# str_len stays the same because that's the length in bytes
return (str_val, pos + str_len)
def unser_array(self, buf, pos):
arr_len, pos = self.unser_int(buf, pos + 1)
arr = []
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 for _ in range(arr_len):
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 arr_item, pos = self.loads_recursive(buf, pos)
arr.append(arr_item)
if not self.mutable:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 arr = tuple(arr)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656
return arr, pos
def unser_object(self, buf, pos):
obj_len, pos = self.unser_int(buf, pos + 1)
if self.mutable:
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 obj = {}
else:
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 keys = []
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 vals = []
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 for _ in range(obj_len):
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 key, pos = self.unser_utf8_string(buf, pos)
val, pos = self.loads_recursive(buf, pos)
if self.mutable:
obj[key] = val
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 keys.append(key)
vals.append(val)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 if not self.mutable:
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 obj = _BunserDict(keys, vals)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 return obj, pos
def unser_template(self, buf, pos):
val_type = _buf_pos(buf, pos + 1)
if val_type != BSER_ARRAY:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise RuntimeError("Expect ARRAY to follow TEMPLATE")
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 # force UTF-8 on keys
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 keys_bunser = Bunser(mutable=self.mutable, value_encoding="utf-8")
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 keys, pos = keys_bunser.unser_array(buf, pos + 1)
nitems, pos = self.unser_int(buf, pos)
arr = []
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 for _ in range(nitems):
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 if self.mutable:
obj = {}
else:
vals = []
for keyidx in range(len(keys)):
if _buf_pos(buf, pos) == BSER_SKIP:
pos += 1
ele = None
else:
ele, pos = self.loads_recursive(buf, pos)
if self.mutable:
key = keys[keyidx]
obj[key] = ele
else:
vals.append(ele)
if not self.mutable:
obj = _BunserDict(keys, vals)
arr.append(obj)
return arr, pos
def loads_recursive(self, buf, pos):
val_type = _buf_pos(buf, pos)
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 if (
val_type == BSER_INT8
or val_type == BSER_INT16
or val_type == BSER_INT32
or val_type == BSER_INT64
):
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 return self.unser_int(buf, pos)
elif val_type == BSER_REAL:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 val = struct.unpack_from(b"=d", buf, pos + 1)[0]
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 return (val, pos + 9)
elif val_type == BSER_TRUE:
return (True, pos + 1)
elif val_type == BSER_FALSE:
return (False, pos + 1)
elif val_type == BSER_NULL:
return (None, pos + 1)
elif val_type == BSER_BYTESTRING:
return self.unser_bytestring(buf, pos)
elif val_type == BSER_UTF8STRING:
return self.unser_utf8_string(buf, pos)
elif val_type == BSER_ARRAY:
return self.unser_array(buf, pos)
elif val_type == BSER_OBJECT:
return self.unser_object(buf, pos)
elif val_type == BSER_TEMPLATE:
return self.unser_template(buf, pos)
else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise ValueError(
"unhandled bser opcode 0x%s"
% binascii.hexlify(val_type).decode("ascii")
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def _pdu_info_helper(buf):
if buf[0:2] == EMPTY_HEADER[0:2]:
bser_version = 1
bser_capabilities = 0
expected_len, pos2 = Bunser.unser_int(buf, 2)
elif buf[0:2] == EMPTY_HEADER_V2[0:2]:
if len(buf) < 8:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise ValueError("Invalid BSER header")
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 bser_version = 2
bser_capabilities = struct.unpack_from("I", buf, 2)[0]
expected_len, pos2 = Bunser.unser_int(buf, 6)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 else:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise ValueError("Invalid BSER header")
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656
return bser_version, bser_capabilities, expected_len, pos2
def pdu_info(buf):
info = _pdu_info_helper(buf)
return info[0], info[1], info[2] + info[3]
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
def pdu_len(buf):
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 info = _pdu_info_helper(buf)
return info[2] + info[3]
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 def loads(buf, mutable=True, value_encoding=None, value_errors=None):
"""Deserialize a BSER-encoded blob.
@param buf: The buffer to deserialize.
@type buf: bytes
@param mutable: Whether to return mutable results.
@type mutable: bool
@param value_encoding: Optional codec to use to decode values. If
unspecified or None, return values as bytestrings.
@type value_encoding: str
@param value_errors: Optional error handler for codec. 'strict' by default.
The other most common argument is 'surrogateescape' on
Python 3. If value_encoding is None, this is ignored.
@type value_errors: str
"""
info = _pdu_info_helper(buf)
expected_len = info[2]
pos = info[3]
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432 if len(buf) != expected_len + pos:
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 raise ValueError(
"bser data len %d != header len %d" % (expected_len + pos, len(buf))
)
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703 bunser = Bunser(
mutable=mutable,
value_encoding=value_encoding,
value_errors=value_errors,
)
Martijn Pieters
fsmonitor: dependencies for new experimental extension...
r28432
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 return bunser.loads_recursive(buf, pos)[0]
def load(fp, mutable=True, value_encoding=None, value_errors=None):
from . import load
Gregory Szorc
fsmonitor: refresh pywatchman with upstream...
r43703
Zack Hricz
fsmonitor: refresh pywatchman to upstream...
r30656 return load.load(fp, mutable, value_encoding, value_errors)