92
92
if TYPE_CHECKING :
93
93
import cffi
94
94
from pathlib import Path
95
+ from typing_extensions import Self
95
96
96
97
# The follow types are classes defined in the Rust code. Ultimately, a Python
97
98
# alternative should be implemented, but for now, the follow lines only serve
@@ -613,6 +614,75 @@ def raise_exception(self) -> None:
613
614
raise RuntimeError (self .text )
614
615
615
616
617
+ class OwnedString (str ):
618
+ """
619
+ A string that owns its own memory.
620
+
621
+ This is used to ensure that the memory is freed when the string is
622
+ destroyed.
623
+
624
+ As this is subclassed from `str`, it can be used in place of a normal string
625
+ in most cases.
626
+ """
627
+
628
+ def __new__ (cls , ptr : cffi .FFI .CData ) -> Self :
629
+ """
630
+ Create a new Owned String.
631
+
632
+ As this is a subclass of the immutable type `str`, we need to override
633
+ the `__new__` method to ensure that the string is initialised correctly.
634
+ """
635
+ s = ffi .string (ptr )
636
+ return super ().__new__ (cls , s if isinstance (s , str ) else s .decode ("utf-8" ))
637
+
638
+ def __init__ (self , ptr : cffi .FFI .CData ) -> None :
639
+ """
640
+ Initialise a new Owned String.
641
+
642
+ Args:
643
+ ptr:
644
+ CFFI data structure.
645
+ """
646
+ self ._ptr = ptr
647
+ s = ffi .string (ptr )
648
+ self ._string = s if isinstance (s , str ) else s .decode ("utf-8" )
649
+
650
+ def __str__ (self ) -> str :
651
+ """
652
+ String representation of the Owned String.
653
+ """
654
+ return self ._string
655
+
656
+ def __repr__ (self ) -> str :
657
+ """
658
+ Debugging string representation of the Owned String.
659
+ """
660
+ return f"<OwnedString: { self ._string !r} , ptr={ self ._ptr !r} >"
661
+
662
+ def __del__ (self ) -> None :
663
+ """
664
+ Destructor for the Owned String.
665
+ """
666
+ string_delete (self )
667
+
668
+ def __eq__ (self , other : object ) -> bool :
669
+ """
670
+ Equality comparison.
671
+
672
+ Args:
673
+ other:
674
+ The object to compare to.
675
+
676
+ Returns:
677
+ Whether the two objects are equal.
678
+ """
679
+ if isinstance (other , OwnedString ):
680
+ return self ._ptr == other ._ptr
681
+ if isinstance (other , str ):
682
+ return self ._string == other
683
+ return super ().__eq__ (other )
684
+
685
+
616
686
def version () -> str :
617
687
"""
618
688
Return the version of the pact_ffi library.
@@ -3000,7 +3070,7 @@ def message_delete(message: Message) -> None:
3000
3070
raise NotImplementedError
3001
3071
3002
3072
3003
- def message_get_contents (message : Message ) -> str :
3073
+ def message_get_contents (message : Message ) -> OwnedString | None :
3004
3074
"""
3005
3075
Get the contents of a `Message` in string form.
3006
3076
@@ -3112,7 +3182,7 @@ def message_set_contents_bin(
3112
3182
raise NotImplementedError
3113
3183
3114
3184
3115
- def message_get_description (message : Message ) -> str :
3185
+ def message_get_description (message : Message ) -> OwnedString :
3116
3186
r"""
3117
3187
Get a copy of the description.
3118
3188
@@ -4196,20 +4266,14 @@ def sync_message_get_provider_state_iter(
4196
4266
raise NotImplementedError
4197
4267
4198
4268
4199
- def string_delete (string : str ) -> None :
4269
+ def string_delete (string : OwnedString ) -> None :
4200
4270
"""
4201
4271
Delete a string previously returned by this FFI.
4202
4272
4203
4273
[Rust
4204
4274
`pactffi_string_delete`](https://docs.rs/pact_ffi/0.4.9/pact_ffi/?search=pactffi_string_delete)
4205
-
4206
- It is explicitly allowed to pass a null pointer to this function; in that
4207
- case the function will do nothing.
4208
-
4209
- # Safety Passing an invalid pointer, or one that was not returned by a FFI
4210
- function can result in undefined behaviour.
4211
4275
"""
4212
- raise NotImplementedError
4276
+ lib . pactffi_string_delete ( string . _ptr )
4213
4277
4214
4278
4215
4279
def create_mock_server (pact_str : str , addr_str : str , * , tls : bool ) -> int :
@@ -4253,7 +4317,7 @@ def create_mock_server(pact_str: str, addr_str: str, *, tls: bool) -> int:
4253
4317
raise NotImplementedError
4254
4318
4255
4319
4256
- def get_tls_ca_certificate () -> str :
4320
+ def get_tls_ca_certificate () -> OwnedString :
4257
4321
"""
4258
4322
Fetch the CA Certificate used to generate the self-signed certificate.
4259
4323
@@ -4267,7 +4331,7 @@ def get_tls_ca_certificate() -> str:
4267
4331
4268
4332
An empty string indicates an error reading the pem file.
4269
4333
"""
4270
- raise NotImplementedError
4334
+ return OwnedString ( lib . pactffi_get_tls_ca_certificate ())
4271
4335
4272
4336
4273
4337
def create_mock_server_for_pact (pact : PactHandle , addr_str : str , * , tls : bool ) -> int :
@@ -5624,7 +5688,7 @@ def message_with_metadata(message_handle: MessageHandle, key: str, value: str) -
5624
5688
raise NotImplementedError
5625
5689
5626
5690
5627
- def message_reify (message_handle : MessageHandle ) -> str :
5691
+ def message_reify (message_handle : MessageHandle ) -> OwnedString :
5628
5692
"""
5629
5693
Reifies the given message.
5630
5694
@@ -6320,7 +6384,7 @@ def verifier_cli_args() -> str:
6320
6384
raise NotImplementedError
6321
6385
6322
6386
6323
- def verifier_logs (handle : VerifierHandle ) -> str :
6387
+ def verifier_logs (handle : VerifierHandle ) -> OwnedString :
6324
6388
"""
6325
6389
Extracts the logs for the verification run.
6326
6390
@@ -6337,7 +6401,7 @@ def verifier_logs(handle: VerifierHandle) -> str:
6337
6401
raise NotImplementedError
6338
6402
6339
6403
6340
- def verifier_logs_for_provider (provider_name : str ) -> str :
6404
+ def verifier_logs_for_provider (provider_name : str ) -> OwnedString :
6341
6405
"""
6342
6406
Extracts the logs for the verification run for the provider name.
6343
6407
@@ -6354,7 +6418,7 @@ def verifier_logs_for_provider(provider_name: str) -> str:
6354
6418
raise NotImplementedError
6355
6419
6356
6420
6357
- def verifier_output (handle : VerifierHandle , strip_ansi : int ) -> str :
6421
+ def verifier_output (handle : VerifierHandle , strip_ansi : int ) -> OwnedString :
6358
6422
"""
6359
6423
Extracts the standard output for the verification run.
6360
6424
@@ -6373,7 +6437,7 @@ def verifier_output(handle: VerifierHandle, strip_ansi: int) -> str:
6373
6437
raise NotImplementedError
6374
6438
6375
6439
6376
- def verifier_json (handle : VerifierHandle ) -> str :
6440
+ def verifier_json (handle : VerifierHandle ) -> OwnedString :
6377
6441
"""
6378
6442
Extracts the verification result as a JSON document.
6379
6443
@@ -6498,7 +6562,7 @@ def matches_string_value(
6498
6562
expected_value : str ,
6499
6563
actual_value : str ,
6500
6564
cascaded : int ,
6501
- ) -> str :
6565
+ ) -> OwnedString :
6502
6566
"""
6503
6567
Determines if the string value matches the given matching rule.
6504
6568
@@ -6529,7 +6593,7 @@ def matches_u64_value(
6529
6593
expected_value : int ,
6530
6594
actual_value : int ,
6531
6595
cascaded : int ,
6532
- ) -> str :
6596
+ ) -> OwnedString :
6533
6597
"""
6534
6598
Determines if the unsigned integer value matches the given matching rule.
6535
6599
@@ -6559,7 +6623,7 @@ def matches_i64_value(
6559
6623
expected_value : int ,
6560
6624
actual_value : int ,
6561
6625
cascaded : int ,
6562
- ) -> str :
6626
+ ) -> OwnedString :
6563
6627
"""
6564
6628
Determines if the signed integer value matches the given matching rule.
6565
6629
@@ -6589,7 +6653,7 @@ def matches_f64_value(
6589
6653
expected_value : float ,
6590
6654
actual_value : float ,
6591
6655
cascaded : int ,
6592
- ) -> str :
6656
+ ) -> OwnedString :
6593
6657
"""
6594
6658
Determines if the floating point value matches the given matching rule.
6595
6659
@@ -6619,7 +6683,7 @@ def matches_bool_value(
6619
6683
expected_value : int ,
6620
6684
actual_value : int ,
6621
6685
cascaded : int ,
6622
- ) -> str :
6686
+ ) -> OwnedString :
6623
6687
"""
6624
6688
Determines if the boolean value matches the given matching rule.
6625
6689
@@ -6651,7 +6715,7 @@ def matches_binary_value( # noqa: PLR0913
6651
6715
actual_value : str ,
6652
6716
actual_value_len : int ,
6653
6717
cascaded : int ,
6654
- ) -> str :
6718
+ ) -> OwnedString :
6655
6719
"""
6656
6720
Determines if the binary value matches the given matching rule.
6657
6721
@@ -6686,7 +6750,7 @@ def matches_json_value(
6686
6750
expected_value : str ,
6687
6751
actual_value : str ,
6688
6752
cascaded : int ,
6689
- ) -> str :
6753
+ ) -> OwnedString :
6690
6754
"""
6691
6755
Determines if the JSON value matches the given matching rule.
6692
6756
0 commit comments