Skip to content

Commit

Permalink
v2.6 - added support for byte serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrmaslanka committed Aug 1, 2021
1 parent 5e8fde5 commit 81e623a
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ here's only the changelog for the version in development

# v2.6

* added support for serializing and unserializing binary values
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ MiniJSON
[![License](https://img.shields.io/pypi/l/minijson)](https://github.com/Dronehub/minijson)


MiniJSON is a codec for a compact binary representation of JSON.
MiniJSON is a codec for a compact binary representation of a superset of JSON (binary values)
are supported.

Usage
-----
Expand Down
6 changes: 6 additions & 0 deletions docs/specification.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ Type Value consists of:
* If value is 23, then it's False
* If value is 24, then next what comes is count of bytes, and then bytes follow. This is to be
interpreted as a signed integer
* If value is 25, then next comes an unsigned char denoting the length of the bytes, and
the remainder is binary data
* If value is 26, then next comes an unsigned short denoting the length of the bytes, and
the remainder is binary data
* If value is 27, then next comes an unsigned int denoting the length of the bytes, and
the remainder is binary data

Coder **should** encode the value as one having the smallest binary representation, but that is not
required. Decoder **must** parse any arbitrary valid string.
29 changes: 26 additions & 3 deletions minijson.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ cdef inline bint can_be_encoded_as_a_dict(dct):
cdef tuple parse_bytes(bytes data, int starting_position):
cdef:
int value_type
int string_length, elements, i, offset, length
unsigned int uint32
int string_length, elements, i, offset
unsigned int uint32, length
int sint32
unsigned short uint16
short sint16
Expand Down Expand Up @@ -264,6 +264,18 @@ cdef tuple parse_bytes(bytes data, int starting_position):
length = data[starting_position+1]
byte_data = data[starting_position+2:starting_position+2+length]
return length+2, int.from_bytes(byte_data, 'big', signed=True)
elif value_type == 25:
length = data[starting_position+1]
byte_data = data[starting_position+2:starting_position+2+length]
return length+2, byte_data
elif value_type == 26:
length, = STRUCT_H.unpack(data[starting_position+1:starting_position+3])
byte_data = data[starting_position+3:starting_position+3+length]
return length+3, byte_data
elif value_type == 27:
length, = STRUCT_L.unpack(data[starting_position+1:starting_position+5])
byte_data = data[starting_position+5:starting_position+5+length]
return length+5, byte_data
else:
raise DecodingError('Unknown sequence type %s!' % (value_type, ))
except (IndexError, struct.error) as e:
Expand Down Expand Up @@ -371,7 +383,7 @@ cdef class MiniJSONEncoder:
"""
cdef:
str field_name
int length
unsigned int length
bytes b_data
if data is None:
cio.write(b'\x08')
Expand All @@ -382,6 +394,17 @@ cdef class MiniJSONEncoder:
elif data is False:
cio.write(b'\x17')
return 1
elif isinstance(data, bytes):
length = len(data)
if length < 256:
cio.write(bytearray([0x19, length]))
cio.write(data)
elif length < 65536:
cio.write(b'\x1A' + struct.pack('>H', length))
cio.write(data)
else:
cio.write(b'\x1B' + struct.pack('>L', length))
cio.write(data)
elif isinstance(data, str):
length = len(data)
if length < 128:
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# coding: utf-8
[metadata]
version = 2.6a1
version = 2.6
name = minijson
long_description = file: README.md
long_description_content_type = text/markdown; charset=UTF-8
Expand Down
21 changes: 21 additions & 0 deletions tests/test_minijson.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest

from minijson import dumps, loads, dumps_object, loads_object, EncodingError, DecodingError, \
switch_default_double, switch_default_float, MiniJSONEncoder

Expand All @@ -13,6 +14,26 @@ def default(self, v):
e = Encoder()
e.encode(2+3j)

def test_bytes(self):
a = {b'test': b'dupa'}
e = MiniJSONEncoder()
b = e.encode(a)
self.assertEqual(loads(b), a)

def test_bytes_26(self):
a = b'x'*256
e = MiniJSONEncoder()
b = e.encode(a)
self.assertEqual(loads(b), a)
self.assertEqual(len(b), 256+3)

def test_bytes_27(self):
e = MiniJSONEncoder()
a = b'x'*65537
b = e.encode(a)
self.assertEqual(loads(b), a)
self.assertEqual(len(b), 65537+5)

def test_encoder_given_default(self):
def encode(v):
return v.real, v.imag
Expand Down

0 comments on commit 81e623a

Please sign in to comment.