Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: Boolean Encoding #20

Merged
merged 1 commit into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ state_vector = Y.encode_state_vector(d2)
diff = Y.encode_state_as_update(d1, state_vector)
Y.apply_update(d2, diff)

with d2.begin_transaction() as txn:
value = d2.get_text('test').to_string(txn)
value = str(d2.get_text('test'))

assert value == "hello world!"
```
Expand Down
13 changes: 6 additions & 7 deletions src/type_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,18 +234,17 @@ fn py_into_any(v: PyObject) -> Option<Any> {
Python::with_gil(|py| -> Option<Any> {
let v = v.as_ref(py);

if let Ok(s) = v.downcast::<pytypes::PyString>() {
let string: String = s.extract().unwrap();
Some(Any::String(string.into_boxed_str()))
if let Ok(b) = v.downcast::<pytypes::PyBool>() {
Some(Any::Bool(b.extract().unwrap()))
} else if let Ok(l) = v.downcast::<pytypes::PyLong>() {
let i: f64 = l.extract().unwrap();
Some(Any::BigInt(i as i64))
Some(Any::BigInt(l.extract().unwrap()))
} else if v.is_none() {
Some(Any::Null)
} else if let Ok(f) = v.downcast::<pytypes::PyFloat>() {
Some(Any::Number(f.extract().unwrap()))
} else if let Ok(b) = v.downcast::<pytypes::PyBool>() {
Some(Any::Bool(b.extract().unwrap()))
} else if let Ok(s) = v.downcast::<pytypes::PyString>() {
let string: String = s.extract().unwrap();
Some(Any::String(string.into_boxed_str()))
} else if let Ok(list) = v.downcast::<pytypes::PyList>() {
let mut result = Vec::with_capacity(list.len());
for value in list.iter() {
Expand Down
54 changes: 54 additions & 0 deletions tests/test_y_doc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from y_py import YDoc
import y_py as Y
import pytest


Expand All @@ -23,3 +24,56 @@ def test_constructor_options():
YDoc(offset_kind="UTF-0xDEADBEEF")
with pytest.raises(ValueError):
YDoc(offset_kind="😬")


def test_encoding():
"""
Tests encoding / decoding all primitive data types in an array.
"""
doc = YDoc()
receiver = YDoc()
array = doc.get_array("test")
contents = [True, 42, "string"]
with doc.begin_transaction() as txn:
array.insert(txn, 0, contents)

state_vec = Y.encode_state_vector(receiver)
update = Y.encode_state_as_update(doc, state_vec)
Y.apply_update(receiver, update)
value = receiver.get_array("test").to_json()
assert value == contents


def test_boolean_encoding():
"""
Makes sure the boolean types are preserved.
Added due to bug where bools turn to ints during encoding /decoding.
"""
doc = YDoc()
receiver = YDoc()
array = doc.get_array("test")
contents = [True]
with doc.begin_transaction() as txn:
array.insert(txn, 0, contents)

state_vec = Y.encode_state_vector(receiver)
update = Y.encode_state_as_update(doc, state_vec)
Y.apply_update(receiver, update)
value = receiver.get_array("test").to_json()
assert type(value[0]) == type(contents[0])


def test_tutorial():
d1 = Y.YDoc()
text = d1.get_text("test")
with d1.begin_transaction() as txn:
text.push(txn, "hello world!")

d2 = Y.YDoc()
state_vector = Y.encode_state_vector(d2)
diff = Y.encode_state_as_update(d1, state_vector)
Y.apply_update(d2, diff)

value = str(d2.get_text("test"))

assert value == "hello world!"
10 changes: 7 additions & 3 deletions y_py.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ class YDoc:
onto `YText` instance.
"""

def encode_state_vector(doc: YDoc) -> List[int]:
StateVector = List[int]

def encode_state_vector(doc: YDoc) -> StateVector:
"""
Encodes a state vector of a given Ypy document into its binary representation using lib0 v1
encoding. State vector is a compact representation of updates performed on a given document and
Expand All @@ -143,7 +145,9 @@ def encode_state_vector(doc: YDoc) -> List[int]:

"""

def encode_state_as_update(doc: YDoc, vector: Optional[List[int]]) -> List[int]:
YDocUpdate = List[int]

def encode_state_as_update(doc: YDoc, vector: Optional[StateVector]) -> YDocUpdate:
"""
Encodes all updates that have happened since a given version `vector` into a compact delta
representation using lib0 v1 encoding. If `vector` parameter has not been provided, generated
Expand All @@ -165,7 +169,7 @@ def encode_state_as_update(doc: YDoc, vector: Optional[List[int]]) -> List[int]:
apply_update(local_doc, remote_delta)
"""

def apply_update(doc: YDoc, diff: List[int]):
def apply_update(doc: YDoc, diff: YDocUpdate):
"""
Applies delta update generated by the remote document replica to a current document. This
method assumes that a payload maintains lib0 v1 encoding format.
Expand Down