Skip to content

Commit

Permalink
Add fbthrift_copy_from to MutableStruct
Browse files Browse the repository at this point in the history
Summary: Add `fbthrift_copy_from()` to MutableStruct.

Reviewed By: ahilger

Differential Revision: D67942525

fbshipit-source-id: ffa228460f35d4989f3c71d241b4d9e12081e8e1
  • Loading branch information
yoney authored and facebook-github-bot committed Jan 8, 2025
1 parent 5dd6eb8 commit 95f7e48
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
1 change: 1 addition & 0 deletions thrift/lib/python/mutable_types.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class MutableStruct(
typing.Iterable[typing.Tuple[str, typing.Any]],
metaclass=MutableStructMeta,
):
def fbthrift_copy_from(self, other: object) -> None: ...
def _to_python(self) -> Struct: ...

class MutableUnion(MutableStructOrUnion, metaclass=MutableUnionMeta): ...
Expand Down
12 changes: 12 additions & 0 deletions thrift/lib/python/mutable_types.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,19 @@ cdef class MutableStruct(MutableStructOrUnion):
assert self._fbthrift_has_struct_instance(self._fbthrift_data)
return self._fbthrift_create(copy.deepcopy(self._fbthrift_data[:-1]))

def fbthrift_copy_from(self, other):
"""
Copies the content of `other` into the current struct.
It resets the current struct and then it assigns each field of `other`
to `self`.
"""
if type(self) is not type(other):
raise TypeError(f"Cannot copy from {type(other)} to {type(self)}")

self.fbthrift_reset()
# Last element is the `MutableStruct` instance, do not copy
self._fbthrift_data[:-1] = (<MutableStruct>other)._fbthrift_data[:-1]

cdef _initStructListWithValues(self, kwargs) except *:
"""
Expand Down
74 changes: 74 additions & 0 deletions thrift/test/thrift-python/struct_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2233,3 +2233,77 @@ def test_match(self) -> None:
self.assertIsNone(y)
case _:
self.fail("Expected match, got none.")

def test_fbthrift_copy_from(self) -> None:
"""
`lhs.fbthrift_copy_from(rhs)` copies the content of the `rhs` struct
into the lhs struct. It is semantically equivalent to assigning each
field of `rhs` to `lhs`."
"""
# Struct with primitive fields
s1 = TestStructAllThriftPrimitiveTypesMutable(
unqualified_bool=True,
optional_byte=0,
unqualified_i16=1,
optional_i32=2,
unqualified_i64=3,
optional_float=4.0,
unqualified_double=5.0,
optional_string="abc",
)

s2 = TestStructAllThriftPrimitiveTypesMutable()
self.assertNotEqual(s1, s2)
s2.fbthrift_copy_from(s1)
self.assertEqual(s1, s2)

# Struct with container fields
s3 = TestStructAllThriftContainerTypesMutable(
unqualified_list_i32=to_thrift_list([1, 2, 3]),
optional_set_string=to_thrift_set({"a", "b", "c"}),
unqualified_map_string_i32=to_thrift_map({"a": 1, "b": 2}),
)

s4 = TestStructAllThriftContainerTypesMutable()
self.assertNotEqual(s3, s4)
s4.fbthrift_copy_from(s3)
self.assertEqual(s3, s4)

# Container assignment is refernce semantics, after `fbthrift_copy_from()`
# s3 and s4 container fields are the "same" containers.
self.assertEqual([1, 2, 3], s3.unqualified_list_i32)
self.assertEqual([1, 2, 3], s4.unqualified_list_i32)

s3.unqualified_list_i32.append(4)

self.assertEqual([1, 2, 3, 4], s3.unqualified_list_i32)
self.assertEqual([1, 2, 3, 4], s4.unqualified_list_i32)

# Struct with struct fields
n2 = TestStructNested_2_Mutable(i32_field=2)
n1 = TestStructNested_1_Mutable(i32_field=3, nested_2=n2)
s5 = TestStructNested_0_Mutable(i32_field=5, nested_1=n1)

s6 = TestStructNested_0_Mutable()
self.assertNotEqual(s5, s6)
s6.fbthrift_copy_from(s5)
self.assertEqual(s5, s6)

# Struct assignment is refernce semantics, after `fbthrift_copy_from()`
# s5 and s4 struct fields are the "same" structs.
self.assertEqual(3, s5.nested_1.i32_field)
self.assertEqual(3, s6.nested_1.i32_field)

s5.nested_1.i32_field = 33

self.assertEqual(33, s5.nested_1.i32_field)
self.assertEqual(33, s6.nested_1.i32_field)

# `lhs` and `rhs` must be the same type
s7 = TestStructAllThriftPrimitiveTypesMutable()
with self.assertRaisesRegex(
TypeError,
"Cannot copy from.*TestStructAllThriftContainerTypes.*to"
".*TestStructAllThriftPrimitiveTypes",
):
s7.fbthrift_copy_from(TestStructAllThriftContainerTypesMutable())

0 comments on commit 95f7e48

Please sign in to comment.