##// END OF EJS Templates
overlayworkingctx: rename misleadingly named `isempty()` method...
overlayworkingctx: rename misleadingly named `isempty()` method This method is only about whether there are file changes, not about whether the commit will be empty or not. One user of the method was incorrectly assuming the latter meaning, leading to the bug for which a test case was added in D8727. I’ve added a FIXME to the code. The original motivation for the rename was that I want to add `committablectx.isempty()`, that properly checks if a commit will be empty, using the exact same logic as in `repo.commit()`, and I wanted to avoid a name clash. Differential Revision: https://phab.mercurial-scm.org/D8728

File last commit:

r44440:c8a51a90 default
r45647:83f75f1e 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)