From fbc7ea111b80d2c075f3623d05056c6da7f9efc0 Mon Sep 17 00:00:00 2001 From: waidhoferj Date: Wed, 13 Jul 2022 20:18:58 -0700 Subject: [PATCH 1/3] before rewrite --- src/shared_types.rs | 45 ++++++++++++++++++++++++++++++++++++++++- src/type_conversions.rs | 29 ++++++++++---------------- tests/test_y_map.py | 11 ++++++++++ 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/shared_types.rs b/src/shared_types.rs index 471cf17..a35db52 100644 --- a/src/shared_types.rs +++ b/src/shared_types.rs @@ -1,12 +1,14 @@ use crate::{ + type_conversions::{py_into_any, MultipleIntegrationError}, y_array::YArray, y_map::YMap, y_text::YText, y_xml::{YXmlElement, YXmlText}, }; +use lib0::any::Any; use pyo3::create_exception; use pyo3::{exceptions::PyException, prelude::*}; -use std::{convert::TryFrom, fmt::Display}; +use std::{collections::HashMap, convert::TryFrom, fmt::Display}; use yrs::types::TYPE_REFS_XML_TEXT; use yrs::types::{TypeRefs, TYPE_REFS_ARRAY, TYPE_REFS_MAP, TYPE_REFS_TEXT}; use yrs::{types::TYPE_REFS_XML_ELEMENT, SubscriptionId}; @@ -132,3 +134,44 @@ impl TryFrom for Shared { }) } } + +impl TryFrom for Any { + type Error = PyErr; + + fn try_from(shared: Shared) -> Result { + const integrated_message: &str = "All shared types should be preliminary at this point."; + + if shared.is_prelim() { + Python::with_gil(|py| match shared { + Shared::Text(text) => match text.borrow(py).0 { + SharedType::Prelim(text) => Ok(Any::String(text.into_boxed_str())), + SharedType::Integrated(_) => unreachable!(integrated_message), + }, + Shared::Array(array) => match array.borrow(py).0 { + SharedType::Prelim(array) => { + let any_array: PyResult> = + array.into_iter().map(|v| py_into_any(v)).collect(); + Ok(Any::Array(any_array?.into_boxed_slice())) + } + SharedType::Integrated(_) => unreachable!(integrated_message), + }, + Shared::Map(dict) => match dict.borrow(py).0 { + SharedType::Prelim(dict) => { + let any_dict: PyResult> = dict + .into_iter() + .map(|(k, v)| py_into_any(v).map(|v| (k, v))) + .collect(); + Ok(Any::Map(Box::new(any_dict?))) + } + SharedType::Integrated(_) => unreachable!(integrated_message), + }, + Shared::XmlElement(xml) => unimplemented!(), + Shared::XmlText(xml) => unimplemented!(), + }) + } else { + Err(MultipleIntegrationError::new_err(format!( + "Cannot integrate a nested Ypy object because is already integrated into a YDoc: {shared}" + ))) + } + } +} diff --git a/src/type_conversions.rs b/src/type_conversions.rs index 7eecfcf..169e008 100644 --- a/src/type_conversions.rs +++ b/src/type_conversions.rs @@ -7,6 +7,7 @@ use pyo3::types as pytypes; use pyo3::types::PyList; use std::collections::HashMap; use std::convert::TryFrom; +use std::convert::TryInto; use std::ops::Deref; use yrs::block::{ItemContent, Prelim}; use yrs::types::Events; @@ -244,25 +245,17 @@ pub(crate) fn py_into_any(v: PyObject) -> PyResult { .collect(); result.map(|res| Any::Array(res.into_boxed_slice())) } else if let Ok(dict) = v.downcast::() { - if let Ok(shared) = Shared::extract(v) { - Err(MultipleIntegrationError::new_err(format!( - "Cannot integrate a nested Ypy object because is already integrated into a YDoc: {shared}" - ))) - } else { - let result: PyResult> = dict - .iter() - .map(|(k, v)| { - let key: String = k.extract()?; - let value = py_into_any(v.into())?; - Ok((key, value)) - }) - .collect(); - result.map(|res| Any::Map(Box::new(res))) - } + let result: PyResult> = dict + .iter() + .map(|(k, v)| { + let key: String = k.extract()?; + let value = py_into_any(v.into())?; + Ok((key, value)) + }) + .collect(); + result.map(|res| Any::Map(Box::new(res))) } else if let Ok(v) = Shared::try_from(PyObject::from(v)) { - Err(MultipleIntegrationError::new_err(format!( - "Cannot integrate a nested Ypy object because is already integrated into a YDoc: {v}" - ))) + v.try_into() } else { Err(PyTypeError::new_err(format!( "Cannot integrate this type into a YDoc: {v}" diff --git a/tests/test_y_map.py b/tests/test_y_map.py index 3a9b40a..7a53696 100644 --- a/tests/test_y_map.py +++ b/tests/test_y_map.py @@ -254,3 +254,14 @@ def callback(e: list): container["inner"].set(txn, "don't show up", 1) assert events is None + + +def test_borrow_issue(): + doc = Y.YDoc() + wrapper = doc.get_map("wrapper") + inner = Y.YMap({"Foo": "Bar"}) + + with doc.begin_transaction() as txn: + wrapper.set(txn, "inner", inner) + + print(wrapper) From 73c8c96c734e60b37060bd54f47375d6892e1297 Mon Sep 17 00:00:00 2001 From: waidhoferj Date: Fri, 15 Jul 2022 00:04:18 -0700 Subject: [PATCH 2/3] possible solution --- src/shared_types.rs | 81 +++++++++++-------- src/type_conversions.rs | 168 ++++++++++++---------------------------- src/y_array.rs | 10 ++- src/y_map.rs | 4 +- src/y_text.rs | 8 +- tests/test_y_map.py | 6 +- 6 files changed, 111 insertions(+), 166 deletions(-) diff --git a/src/shared_types.rs b/src/shared_types.rs index a35db52..7fc060a 100644 --- a/src/shared_types.rs +++ b/src/shared_types.rs @@ -1,5 +1,5 @@ use crate::{ - type_conversions::{py_into_any, MultipleIntegrationError}, + type_conversions::{MultipleIntegrationError, PyObjectWrapper}, y_array::YArray, y_map::YMap, y_text::YText, @@ -8,7 +8,11 @@ use crate::{ use lib0::any::Any; use pyo3::create_exception; use pyo3::{exceptions::PyException, prelude::*}; -use std::{collections::HashMap, convert::TryFrom, fmt::Display}; +use std::{ + collections::HashMap, + convert::{TryFrom, TryInto}, + fmt::Display, +}; use yrs::types::TYPE_REFS_XML_TEXT; use yrs::types::{TypeRefs, TYPE_REFS_ARRAY, TYPE_REFS_MAP, TYPE_REFS_TEXT}; use yrs::{types::TYPE_REFS_XML_ELEMENT, SubscriptionId}; @@ -53,14 +57,14 @@ pub enum SubId { } #[derive(Clone)] -pub enum SharedType { - Integrated(T), +pub enum SharedType { + Integrated(I), Prelim(P), } -impl SharedType { +impl SharedType { #[inline(always)] - pub fn new(value: T) -> Self { + pub fn new(value: I) -> Self { SharedType::Integrated(value) } @@ -70,6 +74,16 @@ impl SharedType { } } +impl SharedType { + /// Extracts the preliminary value if it exists and replaces it with a default value. + fn take_prelim(&mut self) -> Option

{ + match self { + SharedType::Integrated(_) => None, + SharedType::Prelim(p) => Some(std::mem::take(p)), + } + } +} + #[derive(FromPyObject)] pub enum Shared { Text(Py), @@ -139,34 +153,35 @@ impl TryFrom for Any { type Error = PyErr; fn try_from(shared: Shared) -> Result { - const integrated_message: &str = "All shared types should be preliminary at this point."; - if shared.is_prelim() { - Python::with_gil(|py| match shared { - Shared::Text(text) => match text.borrow(py).0 { - SharedType::Prelim(text) => Ok(Any::String(text.into_boxed_str())), - SharedType::Integrated(_) => unreachable!(integrated_message), - }, - Shared::Array(array) => match array.borrow(py).0 { - SharedType::Prelim(array) => { - let any_array: PyResult> = - array.into_iter().map(|v| py_into_any(v)).collect(); - Ok(Any::Array(any_array?.into_boxed_slice())) - } - SharedType::Integrated(_) => unreachable!(integrated_message), - }, - Shared::Map(dict) => match dict.borrow(py).0 { - SharedType::Prelim(dict) => { - let any_dict: PyResult> = dict - .into_iter() - .map(|(k, v)| py_into_any(v).map(|v| (k, v))) - .collect(); - Ok(Any::Map(Box::new(any_dict?))) - } - SharedType::Integrated(_) => unreachable!(integrated_message), - }, - Shared::XmlElement(xml) => unimplemented!(), - Shared::XmlText(xml) => unimplemented!(), + Python::with_gil(|py| { + match shared { + Shared::Text(text) => { + let content = text + .borrow_mut(py) + .0 + .take_prelim() + .unwrap() + .into_boxed_str(); + Ok(Any::String(content)) + } + + Shared::Array(array) => { + let content = array.borrow_mut(py).0.take_prelim().unwrap(); + let any_array: Result, _> = + content.into_iter().map(|v| PyObjectWrapper(v).try_into()).collect(); + Ok(Any::Array(any_array?.into_boxed_slice())) + } + Shared::Map(dict) => { + let content = dict.borrow_mut(py).0.take_prelim().unwrap(); + let any_dict: PyResult> = content + .into_iter() + .map(|(k, v)| PyObjectWrapper(v).try_into().map(|v| (k, v))) + .collect(); + Ok(Any::Map(Box::new(any_dict?))) + } + Shared::XmlElement(_) | Shared::XmlText(_) => unreachable!("As defined in Shared::is_prelim(), neither XML type can ever exist outside a YDoc"), + } }) } else { Err(MultipleIntegrationError::new_err(format!( diff --git a/src/type_conversions.rs b/src/type_conversions.rs index 169e008..b508738 100644 --- a/src/type_conversions.rs +++ b/src/type_conversions.rs @@ -147,7 +147,7 @@ pub(crate) struct PyObjectWrapper(pub PyObject); impl Prelim for PyObjectWrapper { fn into_content(self, _txn: &mut Transaction) -> (ItemContent, Option) { - let content = match py_into_any(self.0.clone()) { + let content = match PyObjectWrapper(self.0.clone()).try_into() { Ok(any) => ItemContent::Any(vec![any]), Err(err) => { if Python::with_gil(|py| err.is_instance_of::(py)) { @@ -203,7 +203,7 @@ impl Prelim for PyObjectWrapper { let mut y_map = v.borrow_mut(py); if let SharedType::Prelim(entries) = y_map.0.to_owned() { for (k, v) in entries { - map.insert(txn, k, PyValueWrapper(v)); + map.insert(txn, k, PyObjectWrapper(v)); } } y_map.0 = SharedType::Integrated(map.clone()); @@ -216,52 +216,56 @@ impl Prelim for PyObjectWrapper { } } -const MAX_JS_NUMBER: i64 = 2_i64.pow(53) - 1; -/// Converts a Python object into an integrated Any type. -pub(crate) fn py_into_any(v: PyObject) -> PyResult { - Python::with_gil(|py| { - let v = v.as_ref(py); +impl TryFrom for Any { + type Error = PyErr; + + fn try_from(wrapper: PyObjectWrapper) -> Result { + const MAX_JS_NUMBER: i64 = 2_i64.pow(53) - 1; + let py_obj = wrapper.0; + Python::with_gil(|py| { + let v = py_obj.as_ref(py); - if let Ok(b) = v.downcast::() { - Ok(Any::Bool(b.extract().unwrap())) - } else if let Ok(l) = v.downcast::() { - let num: i64 = l.extract().unwrap(); - if num > MAX_JS_NUMBER { - Ok(Any::BigInt(num)) + if let Ok(b) = v.downcast::() { + Ok(Any::Bool(b.extract().unwrap())) + } else if let Ok(l) = v.downcast::() { + let num: i64 = l.extract().unwrap(); + if num > MAX_JS_NUMBER { + Ok(Any::BigInt(num)) + } else { + Ok(Any::Number(num as f64)) + } + } else if v.is_none() { + Ok(Any::Null) + } else if let Ok(f) = v.downcast::() { + Ok(Any::Number(f.extract().unwrap())) + } else if let Ok(s) = v.downcast::() { + let string: String = s.extract().unwrap(); + Ok(Any::String(string.into_boxed_str())) + } else if let Ok(list) = v.downcast::() { + let result: PyResult> = list + .into_iter() + .map(|py_val| PyObjectWrapper(py_val.into()).try_into()) + .collect(); + result.map(|res| Any::Array(res.into_boxed_slice())) + } else if let Ok(dict) = v.downcast::() { + let result: PyResult> = dict + .iter() + .map(|(k, v)| { + let key: String = k.extract()?; + let value = PyObjectWrapper(v.into()).try_into()?; + Ok((key, value)) + }) + .collect(); + result.map(|res| Any::Map(Box::new(res))) + } else if let Ok(v) = Shared::try_from(PyObject::from(v)) { + v.try_into() } else { - Ok(Any::Number(num as f64)) + Err(PyTypeError::new_err(format!( + "Cannot integrate this type into a YDoc: {v}" + ))) } - } else if v.is_none() { - Ok(Any::Null) - } else if let Ok(f) = v.downcast::() { - Ok(Any::Number(f.extract().unwrap())) - } else if let Ok(s) = v.downcast::() { - let string: String = s.extract().unwrap(); - Ok(Any::String(string.into_boxed_str())) - } else if let Ok(list) = v.downcast::() { - let result: PyResult> = list - .into_iter() - .map(|py_val| py_into_any(py_val.into())) - .collect(); - result.map(|res| Any::Array(res.into_boxed_slice())) - } else if let Ok(dict) = v.downcast::() { - let result: PyResult> = dict - .iter() - .map(|(k, v)| { - let key: String = k.extract()?; - let value = py_into_any(v.into())?; - Ok((key, value)) - }) - .collect(); - result.map(|res| Any::Map(Box::new(res))) - } else if let Ok(v) = Shared::try_from(PyObject::from(v)) { - v.try_into() - } else { - Err(PyTypeError::new_err(format!( - "Cannot integrate this type into a YDoc: {v}" - ))) - } - }) + }) + } } impl ToPython for Any { @@ -321,77 +325,3 @@ pub(crate) fn events_into_py(txn: &Transaction, events: &Events) -> PyObject { PyList::new(py, py_events).into() }) } - -pub struct PyValueWrapper(pub PyObject); - -impl Prelim for PyValueWrapper { - fn into_content(self, _txn: &mut Transaction) -> (ItemContent, Option) { - let content = match py_into_any(self.0.clone()) { - Ok(any) => ItemContent::Any(vec![any]), - Err(err) => { - if Python::with_gil(|py| err.is_instance_of::(py)) { - let shared = Shared::try_from(self.0.clone()).unwrap(); - if shared.is_prelim() { - let branch = Branch::new(shared.type_ref(), None); - ItemContent::Type(branch) - } else { - Python::with_gil(|py| err.restore(py)); - ItemContent::Any(vec![]) - } - } else { - Python::with_gil(|py| err.restore(py)); - ItemContent::Any(vec![]) - } - } - }; - - let this = if let ItemContent::Type(_) = &content { - Some(self) - } else { - None - }; - - (content, this) - } - - fn integrate(self, txn: &mut Transaction, inner_ref: BranchPtr) { - if let Ok(shared) = Shared::try_from(self.0) { - if shared.is_prelim() { - Python::with_gil(|py| { - match shared { - Shared::Text(v) => { - let text = Text::from(inner_ref); - let mut y_text = v.borrow_mut(py); - - if let SharedType::Prelim(v) = y_text.0.to_owned() { - text.push(txn, v.as_str()); - } - y_text.0 = SharedType::Integrated(text.clone()); - } - Shared::Array(v) => { - let array = Array::from(inner_ref); - let mut y_array = v.borrow_mut(py); - if let SharedType::Prelim(items) = y_array.0.to_owned() { - let len = array.len(); - YArray::insert_multiple_at(&array, txn, len, items); - } - y_array.0 = SharedType::Integrated(array.clone()); - } - Shared::Map(v) => { - let map = Map::from(inner_ref); - let mut y_map = v.borrow_mut(py); - - if let SharedType::Prelim(entries) = y_map.0.to_owned() { - for (k, v) in entries { - map.insert(txn, k, PyValueWrapper(v)); - } - } - y_map.0 = SharedType::Integrated(map.clone()); - } - Shared::XmlElement(_) | Shared::XmlText(_) => unreachable!("As defined in Shared::is_prelim(), neither XML type can ever exist outside a YDoc"), - } - }) - } - } - } -} diff --git a/src/y_array.rs b/src/y_array.rs index 5344276..d794417 100644 --- a/src/y_array.rs +++ b/src/y_array.rs @@ -10,9 +10,10 @@ use crate::y_transaction::YTransaction; use super::shared_types::SharedType; use crate::type_conversions::ToPython; +use lib0::any::Any; use pyo3::exceptions::PyIndexError; -use crate::type_conversions::{py_into_any, PyObjectWrapper}; +use crate::type_conversions::PyObjectWrapper; use pyo3::prelude::*; use pyo3::types::{PyList, PySlice, PySliceIndices}; use yrs::types::array::{ArrayEvent, ArrayIter}; @@ -103,7 +104,8 @@ impl YArray { pub fn insert(&mut self, txn: &mut YTransaction, index: u32, item: PyObject) -> PyResult<()> { match &mut self.0 { SharedType::Integrated(array) if array.len() >= index => { - py_into_any(item).map(|any| array.insert(txn, index, any)) + array.insert(txn, index, PyObjectWrapper(item)); + Ok(()) } SharedType::Prelim(vec) if vec.len() >= index as usize => { Ok(vec.insert(index as usize, item)) @@ -348,9 +350,9 @@ impl YArray { let mut j = index; let mut i = 0; while i < src.len() { - let mut anys = Vec::default(); + let mut anys: Vec = Vec::default(); while i < src.len() { - if let Ok(any) = py_into_any(src[i].clone()) { + if let Ok(any) = PyObjectWrapper(src[i].clone()).try_into() { anys.push(any); i += 1; } else { diff --git a/src/y_map.rs b/src/y_map.rs index 7e4f3f5..71507c1 100644 --- a/src/y_map.rs +++ b/src/y_map.rs @@ -12,7 +12,7 @@ use crate::shared_types::{ DeepSubscription, DefaultPyErr, PreliminaryObservationException, ShallowSubscription, SharedType, SubId, }; -use crate::type_conversions::{events_into_py, PyValueWrapper, ToPython}; +use crate::type_conversions::{events_into_py, PyObjectWrapper, ToPython}; use crate::y_transaction::YTransaction; /// Collection used to store key-value entries in an unordered manner. Keys are always represented @@ -103,7 +103,7 @@ impl YMap { pub fn set(&mut self, txn: &mut YTransaction, key: &str, value: PyObject) { match &mut self.0 { SharedType::Integrated(v) => { - v.insert(txn, key.to_string(), PyValueWrapper(value)); + v.insert(txn, key.to_string(), PyObjectWrapper(value)); } SharedType::Prelim(v) => { v.insert(key.to_string(), value); diff --git a/src/y_text.rs b/src/y_text.rs index 42839ff..d8d9a00 100644 --- a/src/y_text.rs +++ b/src/y_text.rs @@ -2,13 +2,13 @@ use crate::shared_types::{ DeepSubscription, DefaultPyErr, IntegratedOperationException, PreliminaryObservationException, ShallowSubscription, SharedType, SubId, }; -use crate::type_conversions::py_into_any; -use crate::type_conversions::{events_into_py, ToPython}; +use crate::type_conversions::{events_into_py, PyObjectWrapper, ToPython}; use crate::y_transaction::YTransaction; use lib0::any::Any; use pyo3::prelude::*; use pyo3::types::PyList; use std::collections::HashMap; +use std::convert::TryInto; use std::rc::Rc; use yrs::types::text::TextEvent; use yrs::types::Attrs; @@ -136,7 +136,7 @@ impl YText { ) -> PyResult<()> { match &mut self.0 { SharedType::Integrated(text) => { - let content = py_into_any(embed)?; + let content = PyObjectWrapper(embed).try_into()?; if let Some(Ok(attrs)) = attributes.map(Self::parse_attrs) { text.insert_embed_with_attributes(txn, index, content, attrs) } else { @@ -250,7 +250,7 @@ impl YText { .into_iter() .map(|(k, v)| { let key = Rc::from(k); - let value = py_into_any(v)?; + let value = PyObjectWrapper(v).try_into()?; Ok((key, value)) }) .collect() diff --git a/tests/test_y_map.py b/tests/test_y_map.py index 7a53696..5b18d06 100644 --- a/tests/test_y_map.py +++ b/tests/test_y_map.py @@ -258,10 +258,8 @@ def callback(e: list): def test_borrow_issue(): doc = Y.YDoc() - wrapper = doc.get_map("wrapper") + wrapper = doc.get_array("wrapper") inner = Y.YMap({"Foo": "Bar"}) with doc.begin_transaction() as txn: - wrapper.set(txn, "inner", inner) - - print(wrapper) + wrapper.append(txn, inner) From 8d82dc183fb5c6807d7a244bcb578e5fba91cdbd Mon Sep 17 00:00:00 2001 From: waidhoferj Date: Thu, 21 Jul 2022 15:35:30 -0700 Subject: [PATCH 3/3] took out changes to any casting --- pyproject.toml | 2 +- src/shared_types.rs | 60 +---------------------------------------- src/type_conversions.rs | 6 ++++- 3 files changed, 7 insertions(+), 61 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 573adf8..5d44682 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["maturin>=0.13"] +requires = ["maturin>=0.13,<0.14"] build-backend = "maturin" diff --git a/src/shared_types.rs b/src/shared_types.rs index 7fc060a..d660f78 100644 --- a/src/shared_types.rs +++ b/src/shared_types.rs @@ -1,18 +1,12 @@ use crate::{ - type_conversions::{MultipleIntegrationError, PyObjectWrapper}, y_array::YArray, y_map::YMap, y_text::YText, y_xml::{YXmlElement, YXmlText}, }; -use lib0::any::Any; use pyo3::create_exception; use pyo3::{exceptions::PyException, prelude::*}; -use std::{ - collections::HashMap, - convert::{TryFrom, TryInto}, - fmt::Display, -}; +use std::{convert::TryFrom, fmt::Display}; use yrs::types::TYPE_REFS_XML_TEXT; use yrs::types::{TypeRefs, TYPE_REFS_ARRAY, TYPE_REFS_MAP, TYPE_REFS_TEXT}; use yrs::{types::TYPE_REFS_XML_ELEMENT, SubscriptionId}; @@ -74,16 +68,6 @@ impl SharedType { } } -impl SharedType { - /// Extracts the preliminary value if it exists and replaces it with a default value. - fn take_prelim(&mut self) -> Option

{ - match self { - SharedType::Integrated(_) => None, - SharedType::Prelim(p) => Some(std::mem::take(p)), - } - } -} - #[derive(FromPyObject)] pub enum Shared { Text(Py), @@ -148,45 +132,3 @@ impl TryFrom for Shared { }) } } - -impl TryFrom for Any { - type Error = PyErr; - - fn try_from(shared: Shared) -> Result { - if shared.is_prelim() { - Python::with_gil(|py| { - match shared { - Shared::Text(text) => { - let content = text - .borrow_mut(py) - .0 - .take_prelim() - .unwrap() - .into_boxed_str(); - Ok(Any::String(content)) - } - - Shared::Array(array) => { - let content = array.borrow_mut(py).0.take_prelim().unwrap(); - let any_array: Result, _> = - content.into_iter().map(|v| PyObjectWrapper(v).try_into()).collect(); - Ok(Any::Array(any_array?.into_boxed_slice())) - } - Shared::Map(dict) => { - let content = dict.borrow_mut(py).0.take_prelim().unwrap(); - let any_dict: PyResult> = content - .into_iter() - .map(|(k, v)| PyObjectWrapper(v).try_into().map(|v| (k, v))) - .collect(); - Ok(Any::Map(Box::new(any_dict?))) - } - Shared::XmlElement(_) | Shared::XmlText(_) => unreachable!("As defined in Shared::is_prelim(), neither XML type can ever exist outside a YDoc"), - } - }) - } else { - Err(MultipleIntegrationError::new_err(format!( - "Cannot integrate a nested Ypy object because is already integrated into a YDoc: {shared}" - ))) - } - } -} diff --git a/src/type_conversions.rs b/src/type_conversions.rs index b508738..12064c9 100644 --- a/src/type_conversions.rs +++ b/src/type_conversions.rs @@ -114,6 +114,7 @@ impl ToPython for &Change { } } +#[repr(transparent)] struct EntryChangeWrapper<'a>(&'a EntryChange); impl<'a> IntoPy for EntryChangeWrapper<'a> { @@ -143,6 +144,7 @@ impl<'a> IntoPy for EntryChangeWrapper<'a> { } } +#[repr(transparent)] pub(crate) struct PyObjectWrapper(pub PyObject); impl Prelim for PyObjectWrapper { @@ -258,7 +260,9 @@ impl TryFrom for Any { .collect(); result.map(|res| Any::Map(Box::new(res))) } else if let Ok(v) = Shared::try_from(PyObject::from(v)) { - v.try_into() + Err(MultipleIntegrationError::new_err(format!( + "Cannot integrate a nested Ypy object because is already integrated into a YDoc: {v}" + ))) } else { Err(PyTypeError::new_err(format!( "Cannot integrate this type into a YDoc: {v}"