rigetti_pyo3/
traits.rs

1// Copyright 2022 Rigetti Computing
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Macros for implementing trait-related behavior for wrapped types.
16//!
17//! - Implement Rust traits based on inner types.
18//! - Implement "dunder" methods based on wrapper type trait implementations.
19//!   - Note that you can pass `#[derive(Trait)]` as part of the `py_wrap_*` macro input
20
21/// Implement Python comparison for a given type. That type must implement
22/// [`PartialOrd`](std::cmp::PartialOrd).
23#[macro_export]
24macro_rules! impl_compare {
25    ($name: ident) => {
26        #[$crate::pyo3::pymethods]
27        impl $name {
28            /// Implements all the Python comparison operators in terms of the
29            /// Rust [`PartialOrd`](std::cmp::PartialOrd) instance.
30            #![allow(clippy::use_self)]
31            pub fn __richcmp__(&self, object: &Self, cmp: $crate::pyo3::basic::CompareOp) -> bool {
32                let result = ::std::cmp::PartialOrd::partial_cmp(self, object);
33                match cmp {
34                    $crate::pyo3::basic::CompareOp::Lt => {
35                        matches!(result, Some(::std::cmp::Ordering::Less))
36                    }
37                    $crate::pyo3::basic::CompareOp::Le => {
38                        !matches!(result, Some(::std::cmp::Ordering::Greater))
39                    }
40                    $crate::pyo3::basic::CompareOp::Eq => {
41                        matches!(result, Some(::std::cmp::Ordering::Equal))
42                    }
43                    $crate::pyo3::basic::CompareOp::Ne => {
44                        !matches!(result, Some(::std::cmp::Ordering::Equal))
45                    }
46                    $crate::pyo3::basic::CompareOp::Gt => {
47                        matches!(result, Some(::std::cmp::Ordering::Greater))
48                    }
49                    $crate::pyo3::basic::CompareOp::Ge => {
50                        !matches!(result, Some(::std::cmp::Ordering::Less))
51                    }
52                }
53            }
54        }
55    };
56}
57
58/// Implement `__hash__` for types that implement [`Hash`](std::hash::Hash).
59#[macro_export]
60macro_rules! impl_hash {
61    ($name: ident) => {
62        #[$crate::pyo3::pymethods]
63        impl $name {
64            /// Implements `__hash__` for Python in terms of the Rust
65            /// [`Hash`](std::hash::Hash) instance.
66            pub fn __hash__(&self) -> i64 {
67                let mut hasher = ::std::collections::hash_map::DefaultHasher::new();
68                ::std::hash::Hash::hash($crate::PyWrapper::as_inner(self), &mut hasher);
69                let bytes = ::std::hash::Hasher::finish(&hasher).to_ne_bytes();
70                i64::from_ne_bytes(bytes)
71            }
72        }
73    };
74}
75
76/// Implement `__repr__` for wrapper types whose inner type implements [`Debug`](std::fmt::Debug).
77#[macro_export]
78macro_rules! impl_repr {
79    ($name: ident) => {
80        /// Implements `__repr__` for Python in terms of the Rust
81        /// [`Debug`](std::fmt::Debug) instance.
82        #[$crate::pyo3::pymethods]
83        impl $name {
84            pub fn __repr__(&self) -> String {
85                format!("{:?}", $crate::PyWrapper::as_inner(self))
86            }
87        }
88    };
89}
90
91/// Implement `__str__` for wrapper types whose inner type implements [`Display`](std::fmt::Display).
92#[macro_export]
93macro_rules! impl_str {
94    ($name: ident) => {
95        /// Implements `__str__` for Python in terms of the Rust
96        /// [`Display`](std::fmt::Display) instance.
97        #[$crate::pyo3::pymethods]
98        impl $name {
99            pub fn __str__(&self) -> String {
100                format!("{}", $crate::PyWrapper::as_inner(self))
101            }
102        }
103    };
104}
105
106/// Implement [`FromStr`](std::str::FromStr) for wrapper types whose inner type implements [`FromStr`](std::str::FromStr).
107///
108/// The second argument must be a Python error wrapper that implements [`From<E>`], where `E = <$name::Inner as FromStr>::Err`.
109#[macro_export]
110macro_rules! impl_from_str {
111    ($name: ident, $error: ty) => {
112        impl ::std::str::FromStr for $name {
113            type Err = $error;
114            fn from_str(input: &str) -> Result<Self, Self::Err> {
115                <<Self as $crate::PyWrapper>::Inner as ::std::str::FromStr>::from_str(input)
116                    .map(Self::from)
117                    .map_err(
118                        <$error as From<
119                            <<Self as $crate::PyWrapper>::Inner as ::std::str::FromStr>::Err,
120                        >>::from,
121                    )
122            }
123        }
124    };
125}
126
127/// Implement a method `parse` for wrapper types that implement [`FromStr`](std::str::FromStr).
128///
129/// See also: [`impl_from_str`].
130#[macro_export]
131macro_rules! impl_parse {
132    ($name: ident) => {
133        #[$crate::pyo3::pymethods]
134        impl $name {
135            /// Implements a static `parse` method for Python in terms of the
136            /// Rust [`FromStr`](std::str::FromStr) instance.
137            #[staticmethod]
138            pub fn parse(input: &str) -> $crate::pyo3::PyResult<Self> {
139                <Self as std::str::FromStr>::from_str(input)
140                    .map(Self::from)
141                    .map_err($crate::ToPythonError::to_py_err)
142            }
143        }
144    };
145}
146
147/// Implement `AsMut<T>` for a Python wrapper around `T`.
148///
149/// This macro is automatically invoked by [`py_wrap_struct`](crate::py_wrap_struct)
150/// and [`py_wrap_union_enum`](crate::py_wrap_union_enum), and should otherwise only be used if
151/// you need more flexibility and are using [`py_wrap_type`](crate::py_wrap_type) directly.
152#[macro_export]
153macro_rules! impl_as_mut_for_wrapper {
154    ($py_type: ident) => {
155        impl AsMut<<$py_type as $crate::PyWrapper>::Inner> for $py_type {
156            fn as_mut(&mut self) -> &mut <$py_type as $crate::PyWrapper>::Inner {
157                &mut self.0
158            }
159        }
160    };
161}