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

Add EnumIntoPy derive macro #29

Merged
merged 7 commits into from
Dec 5, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Extract solders-primitives into its own crate [(#24)](https://github.com/kevinheavey/solders/pull/24)
- Don't leak custom error types in solders-traits; use ValueError instead [(#26)](https://github.com/kevinheavey/solders/pull/26)
- Improve macro hygiene [(#27)](https://github.com/kevinheavey/solders/pull/27) and [(#28)]([(#27)](https://github.com/kevinheavey/solders/pull/27))
- Add EnumIntoPy derive macro [(#29)](https://github.com/kevinheavey/solders/pull/29)

## [0.10.0] - 2022-10-31

Expand Down
30 changes: 30 additions & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,33 @@ pub fn enum_original_mapping(original: TokenStream, item: TokenStream) -> TokenS
new_stream.extend(from_impl);
TokenStream::from(new_stream)
}

/// Impl IntoPy<PyObject> for an ADT where each variant is a newtype.
///
/// # Example
///
/// ```rust
/// use solders_macros::EnumIntoPy;
///
/// #[derive(PartialEq, Debug, EnumIntoPy)]
/// pub enum Foo {
/// A(u8),
/// B(u8)
/// }
///
#[proc_macro_derive(EnumIntoPy)]
pub fn enum_into_py(item: TokenStream) -> TokenStream {
let ast = parse_macro_input!(item as ItemEnum);
let enum_name = ast.ident;
let variant_names: Vec<Ident> = ast.variants.into_iter().map(|v| v.ident).collect();
let into_py_impl = quote! {
impl IntoPy<PyObject> for #enum_name {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
#(Self::#variant_names(x) => x.into_py(py)),*,
}
}
}
};
into_py_impl.to_token_stream().into()
}
13 changes: 2 additions & 11 deletions primitives/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use solana_sdk::{
},
pubkey::Pubkey as PubkeyOriginal,
};
use solders_macros::{common_methods, richcmp_eq_only};
use solders_macros::{common_methods, richcmp_eq_only, EnumIntoPy};
use solders_traits::{
handle_py_err, impl_display, py_from_bytes_general_via_bincode, pybytes_general_via_bincode,
CommonMethods, PyBytesGeneral, PyErrWrapper, RichcmpEqualityOnly,
Expand Down Expand Up @@ -820,22 +820,13 @@ impl MessageV0 {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, FromPyObject)]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, FromPyObject, EnumIntoPy)]
#[serde(from = "VersionedMessageOriginal", into = "VersionedMessageOriginal")]
pub enum VersionedMessage {
Legacy(Message),
V0(MessageV0),
}

impl IntoPy<PyObject> for VersionedMessage {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::Legacy(m) => m.into_py(py),
Self::V0(m) => m.into_py(py),
}
}
}

impl From<VersionedMessageOriginal> for VersionedMessage {
fn from(v: VersionedMessageOriginal) -> Self {
match v {
Expand Down
13 changes: 2 additions & 11 deletions primitives/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use solana_sdk::{
VersionedTransaction as VersionedTransactionOriginal,
},
};
use solders_macros::{common_methods, richcmp_eq_only};
use solders_macros::{common_methods, richcmp_eq_only, EnumIntoPy};
use solders_traits::{
handle_py_err, impl_display, py_from_bytes_general_via_bincode, pybytes_general_via_bincode,
CommonMethods, RichcmpEqualityOnly,
Expand Down Expand Up @@ -713,22 +713,13 @@ impl From<LegacyOriginal> for Legacy {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromPyObject)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromPyObject, EnumIntoPy)]
#[serde(rename_all = "camelCase", untagged)]
pub enum TransactionVersion {
Legacy(Legacy),
Number(u8),
}

impl IntoPy<PyObject> for TransactionVersion {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::Legacy(v) => v.into_py(py),
Self::Number(v) => v.into_py(py),
}
}
}

impl From<TransactionVersion> for TransactionVersionOriginal {
fn from(v: TransactionVersion) -> Self {
match v {
Expand Down
35 changes: 4 additions & 31 deletions src/rpc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::rpc::tmp_config as rpc_config;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use solana_sdk::commitment_config::CommitmentLevel as CommitmentLevelOriginal;
use solders_macros::{common_methods, richcmp_eq_only};
use solders_macros::{common_methods, richcmp_eq_only, EnumIntoPy};
use solders_primitives::{hash::Hash as SolderHash, pubkey::Pubkey, signature::Signature};
use solders_traits::{
impl_display, py_from_bytes_general_via_cbor, pybytes_general_via_cbor, CommonMethods,
Expand Down Expand Up @@ -874,7 +874,7 @@ impl RpcTransactionLogsFilterMentions {

impl RichcmpEqualityOnly for RpcTransactionLogsFilterMentions {}

#[derive(FromPyObject, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[derive(FromPyObject, Clone, PartialEq, Eq, Serialize, Deserialize, Debug, EnumIntoPy)]
pub enum TransactionLogsFilterWrapper {
Plain(RpcTransactionLogsFilter),
Mentions(RpcTransactionLogsFilterMentions),
Expand Down Expand Up @@ -916,15 +916,6 @@ impl From<rpc_config::RpcTransactionLogsFilter> for TransactionLogsFilterWrapper
}
}

impl IntoPy<PyObject> for TransactionLogsFilterWrapper {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::Plain(f) => f.into_py(py),
Self::Mentions(m) => m.into_py(py),
}
}
}

pyclass_boilerplate!(
/// Configuration object for ``logsSubscribe``.
///
Expand Down Expand Up @@ -1009,7 +1000,7 @@ impl RpcTokenAccountsFilterProgramId {

impl RichcmpEqualityOnly for RpcTokenAccountsFilterProgramId {}

#[derive(FromPyObject, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(FromPyObject, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, EnumIntoPy)]
pub enum RpcTokenAccountsFilterWrapper {
Mint(RpcTokenAccountsFilterMint),
ProgramId(RpcTokenAccountsFilterProgramId),
Expand Down Expand Up @@ -1037,15 +1028,6 @@ impl From<rpc_config::RpcTokenAccountsFilter> for RpcTokenAccountsFilterWrapper
}
}

impl IntoPy<PyObject> for RpcTokenAccountsFilterWrapper {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
RpcTokenAccountsFilterWrapper::Mint(m) => m.into_py(py),
RpcTokenAccountsFilterWrapper::ProgramId(m) => m.into_py(py),
}
}
}

pyclass_boilerplate_with_default!(
/// Configuration object for ``signatureSubscribe``.
///
Expand Down Expand Up @@ -1130,7 +1112,7 @@ impl RpcBlockSubscribeFilterMentions {

impl RichcmpEqualityOnly for RpcBlockSubscribeFilterMentions {}

#[derive(FromPyObject, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[derive(FromPyObject, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, EnumIntoPy)]
pub enum RpcBlockSubscribeFilterWrapper {
All(RpcBlockSubscribeFilter),
MentionsAccountOrProgram(RpcBlockSubscribeFilterMentions),
Expand Down Expand Up @@ -1164,15 +1146,6 @@ impl From<rpc_config::RpcBlockSubscribeFilter> for RpcBlockSubscribeFilterWrappe
}
}

impl IntoPy<PyObject> for RpcBlockSubscribeFilterWrapper {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::All(m) => m.into_py(py),
Self::MentionsAccountOrProgram(m) => m.into_py(py),
}
}
}

pyclass_boilerplate_with_default!(
/// Configuration object for ``blockSubscribe``.
///
Expand Down
31 changes: 4 additions & 27 deletions src/rpc/errors.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
use crate::{
transaction_status::{transaction_status_boilerplate, TransactionErrorType},

};
use solders_traits::{CommonMethods, RichcmpEqualityOnly,};
use crate::transaction_status::{transaction_status_boilerplate, TransactionErrorType};
use derive_more::{From, Into};
use pyo3::{prelude::*, types::PyTuple, PyTypeInfo};
use serde::{Deserialize, Serialize};
use solana_sdk::slot_history::Slot;
use solders_macros::{common_methods, richcmp_eq_only};
use solders_macros::{common_methods, richcmp_eq_only, EnumIntoPy};
use solders_traits::{CommonMethods, RichcmpEqualityOnly};
use std::fmt::Display;

use super::responses::RpcSimulateTransactionResult;
Expand Down Expand Up @@ -335,7 +332,7 @@ impl UnsupportedTransactionVersion {

error_message!(UnsupportedTransactionVersionMessage);

#[derive(FromPyObject, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[derive(FromPyObject, Clone, PartialEq, Eq, Serialize, Deserialize, Debug, EnumIntoPy)]
#[serde(untagged)]
pub enum RpcCustomError {
Fieldless(RpcCustomErrorFieldless),
Expand All @@ -359,26 +356,6 @@ error_message!(MethodNotFoundMessage);
error_message!(InvalidParamsMessage);
error_message!(InternalErrorMessage);

impl IntoPy<PyObject> for RpcCustomError {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::BlockCleanedUp(x) => x.into_py(py),
Self::SendTransactionPreflightFailure(x) => x.into_py(py),
Self::BlockNotAvailable(x) => x.into_py(py),
Self::NodeUnhealthy(x) => x.into_py(py),
Self::TransactionPrecompileVerificationFailure(x) => x.into_py(py),
Self::SlotSkipped(x) => x.into_py(py),
Self::LongTermStorageSlotSkipped(x) => x.into_py(py),
Self::KeyExcludedFromSecondaryIndex(x) => x.into_py(py),
Self::ScanError(x) => x.into_py(py),
Self::BlockStatusNotAvailableYet(x) => x.into_py(py),
Self::MinContextSlotNotReached(x) => x.into_py(py),
Self::UnsupportedTransactionVersion(x) => x.into_py(py),
Self::Fieldless(x) => x.into_py(py),
}
}
}

pub(crate) fn create_errors_mod(py: Python<'_>) -> PyResult<&PyModule> {
let m = PyModule::new(py, "errors")?;
m.add_class::<RpcCustomErrorFieldless>()?;
Expand Down
24 changes: 3 additions & 21 deletions src/rpc/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,20 @@ use pyo3::prelude::*;
use serde::{Deserialize, Serialize};

use derive_more::{From, Into};
use solders_macros::{common_methods, enum_original_mapping, richcmp_eq_only};
use solders_macros::{common_methods, enum_original_mapping, richcmp_eq_only, EnumIntoPy};

use solders_traits::{
impl_display, py_from_bytes_general_via_bincode, pybytes_general_via_bincode, CommonMethods,
RichcmpEqualityOnly,
};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, FromPyObject)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, FromPyObject, EnumIntoPy)]
#[serde(rename_all = "camelCase", untagged)]
pub enum MemcmpEncodedBytes {
Base58(String),
Bytes(Vec<u8>),
}

impl IntoPy<PyObject> for MemcmpEncodedBytes {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::Base58(s) => s.into_py(py),
Self::Bytes(v) => v.into_py(py),
}
}
}

impl From<MemcmpEncodedBytes> for MemcmpEncodedBytesOriginal {
fn from(m: MemcmpEncodedBytes) -> Self {
match m {
Expand Down Expand Up @@ -107,22 +98,13 @@ impl Memcmp {
impl RichcmpEqualityOnly for Memcmp {}
impl CommonMethods<'_> for Memcmp {}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, FromPyObject)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, FromPyObject, EnumIntoPy)]
#[serde(rename_all = "camelCase")]
pub enum RpcFilterType {
DataSize(u64),
Memcmp(Memcmp),
}

impl IntoPy<PyObject> for RpcFilterType {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
RpcFilterType::DataSize(num) => num.into_py(py),
RpcFilterType::Memcmp(mem) => mem.into_py(py),
}
}
}

impl From<RpcFilterType> for RpcFilterTypeOriginal {
fn from(r: RpcFilterType) -> Self {
match r {
Expand Down
12 changes: 2 additions & 10 deletions src/rpc/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use serde_with::{serde_as, skip_serializing_none, DisplayFromStr, FromInto};
use solana_sdk::{
message::Message as MessageOriginal, transaction::Transaction as TransactionOriginal,
};
use solders_macros::{common_methods, richcmp_eq_only, rpc_id_getter};
use solders_macros::{common_methods, richcmp_eq_only, rpc_id_getter, EnumIntoPy};

use crate::{Signature, SolderHash};

Expand Down Expand Up @@ -2709,19 +2709,11 @@ zero_param_req_def!(VoteSubscribe);

macro_rules ! pyunion {
($name:ident, $($variant:ident),+) => {
#[derive(FromPyObject, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(FromPyObject, Clone, Debug, PartialEq, Serialize, Deserialize, EnumIntoPy)]
#[serde(tag = "method", rename_all = "camelCase")]
pub enum $name {
$($variant($variant),)+
}

impl IntoPy<PyObject> for $name {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
$(Self::$variant(x) => x.into_py(py),)+
}
}
}
}
}

Expand Down
Loading