From 1c45b9e38ba868675d22496f574a7e693ed80b27 Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Fri, 24 Jan 2025 16:43:30 +0100 Subject: [PATCH] put pyo3 away for now --- androscalpel/Cargo.toml | 11 ++-- androscalpel/src/annotation.rs | 29 +++++---- androscalpel/src/apk.rs | 27 ++++---- androscalpel/src/class.rs | 41 ++++++------ androscalpel/src/code.rs | 21 +++--- androscalpel/src/dex_id.rs | 105 +++++++++++++++++------------- androscalpel/src/dex_string.rs | 13 ++-- androscalpel/src/field.rs | 33 +++++----- androscalpel/src/hiddenapi.rs | 7 +- androscalpel/src/instructions.rs | 23 +++---- androscalpel/src/lib.rs | 4 ++ androscalpel/src/method.rs | 45 ++++++------- androscalpel/src/method_handle.rs | 7 +- androscalpel/src/scalar.rs | 90 ++++++++++++------------- androscalpel/src/value.rs | 7 +- 15 files changed, 248 insertions(+), 215 deletions(-) diff --git a/androscalpel/Cargo.toml b/androscalpel/Cargo.toml index d224f54..7817053 100644 --- a/androscalpel/Cargo.toml +++ b/androscalpel/Cargo.toml @@ -14,8 +14,8 @@ androscalpel_serializer = { version = "0.1.0", path = "../androscalpel_serialize anyhow = { version = "1.0.75", features = ["backtrace"] } apk_frauder = { version = "0.1.0", path = "../apk_frauder" } log = "0.4.20" -pyo3 = { version = "0.23.4", features = ["anyhow", "abi3-py38"] } -pyo3-log = "0.12.1" +pyo3 = { version = "0.23.4", features = ["anyhow", "abi3-py38", "extension-module"], optional = true} +pyo3-log = { version = "0.12.1", optional = true} rayon = "1.9.0" serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" @@ -24,6 +24,7 @@ sha1 = "0.10.6" [dev-dependencies] pretty_assertions = "1.4.1" -#[features] -#extension-module = ["pyo3/extension-module"] -#default = [""] +[features] +default = [] +# TODO: need refactoring to https://github.com/PyO3/pyo3/issues/2935#issuecomment-2560930677 or cfg_eval https://github.com/rust-lang/rust/issues/82679 +python = ["pyo3", "pyo3-log"] diff --git a/androscalpel/src/annotation.rs b/androscalpel/src/annotation.rs index 68baed1..bff2abd 100644 --- a/androscalpel/src/annotation.rs +++ b/androscalpel/src/annotation.rs @@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; +#[cfg(feature = "python")] use pyo3::prelude::*; use crate::hashmap_vectorize; @@ -11,28 +12,28 @@ use crate::{ }; /// Annotation with a visibility -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct DexAnnotationItem { // TODO: the get/set will probably be wonky on the python side when edditing /// The actual annotation - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub annotation: DexAnnotation, // TODO: enforce exclusivity /// If the annotation visibility is set to build - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub visibility_build: bool, /// If the annotation visibility is set to runtime - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub visibility_runtime: bool, /// If the annotation visibility is set to system - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub visibility_system: bool, } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexAnnotationItem { - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(annotation: DexAnnotation) -> Self { Self { annotation, @@ -101,7 +102,7 @@ impl DexAnnotationItem { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } @@ -122,23 +123,23 @@ impl VisitableMut for DexAnnotationItem { } /// An annotation. -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct DexAnnotation { // TODO: check the relation between type and encoded_value. /// The type of the annotation. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub type_: IdType, // TODO: the get/set will probably be wonky on the python side when edditing /// The annotation elements. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] #[serde(with = "hashmap_vectorize")] pub elements: HashMap, // TODO: check MemberName syntax? } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexAnnotation { - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(type_: IdType, elements: HashMap) -> Self { Self { type_, elements } } @@ -218,7 +219,7 @@ impl DexAnnotation { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } diff --git a/androscalpel/src/apk.rs b/androscalpel/src/apk.rs index 062eca0..13bc925 100644 --- a/androscalpel/src/apk.rs +++ b/androscalpel/src/apk.rs @@ -8,8 +8,8 @@ use std::io::Cursor; use std::path::PathBuf; use log::info; -use pyo3::prelude::*; -use pyo3::types::PyBytes; +#[cfg(feature = "python")] +use pyo3::{prelude::*, types::PyBytes}; use crate::ins::CallSite; use crate::instructions; @@ -32,7 +32,7 @@ pub struct DexFile { } /// Represent an apk. -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)] pub struct Apk { pub dex_files: HashMap, // TODO: use accessort for chache invalidation @@ -2981,9 +2981,9 @@ impl Apk { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl Apk { - #[new] + #[cfg_attr(feature = "python", new)] pub fn new() -> Self { // TODO take argument and dispatch to load_apk or load_apk_bin Self { @@ -2993,8 +2993,8 @@ impl Apk { /// Load all android files in an application. /// This **does not include any .dex file that android would not load. - #[staticmethod] - #[pyo3(signature = (apk, label_each_ins=false, cache=false))] + #[cfg_attr(feature = "python", staticmethod)] + #[cfg_attr(feature = "python", pyo3(signature = (apk, label_each_ins=false, cache=false)))] pub fn load_apk(apk: PathBuf, label_each_ins: bool, cache: bool) -> Result { let file = File::open(apk)?; let mut apk_z = ZipFileReader::new(file); @@ -3013,8 +3013,8 @@ impl Apk { /// Load all android files in an application. /// This **does not include any .dex file that android would not load. - #[staticmethod] - #[pyo3(signature = (apk, label_each_ins=false, cache=false))] + #[cfg_attr(feature = "python", staticmethod)] + #[cfg_attr(feature = "python", pyo3(signature = (apk, label_each_ins=false, cache=false)))] pub fn load_apk_bin(apk: &[u8], label_each_ins: bool, cache: bool) -> Result { let mut apk_z = ZipFileReader::new(Cursor::new(apk)); let mut apk = Self::default(); @@ -3039,7 +3039,7 @@ impl Apk { /// - `label_each_ins`: if set to true, insert a label before each instruction /// indicating the instruction address /// - `cache`: if set to true, copy and cache the binary data format. - #[pyo3(signature = (name, data, label_each_ins=false, cache=false))] + #[cfg_attr(feature = "python", pyo3(signature = (name, data, label_each_ins=false, cache=false)))] pub fn add_dex_file( &mut self, name: &str, @@ -3096,7 +3096,7 @@ impl Apk { Ok(()) } - #[pyo3(signature = (method_id, code=None, dex_file=None))] + #[cfg_attr(feature = "python", pyo3(signature = (method_id, code=None, dex_file=None)))] pub fn set_method_code( &mut self, method_id: IdMethod, @@ -3131,6 +3131,7 @@ impl Apk { Ok(()) } + #[cfg(feature = "python")] #[pyo3(name = "gen_raw_dex")] //Sad GIL noise pub fn py_gen_raw_dex(&self, py: Python<'_>) -> Result> { Ok(self @@ -3144,12 +3145,12 @@ impl Apk { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[pyo3(signature = (class, dex_file=None))] + #[cfg_attr(feature = "python", pyo3(signature = (class, dex_file=None)))] pub fn remove_class(&mut self, class: &IdType, dex_file: Option<&str>) -> Result<()> { if let Some(dex_file) = dex_file { self.dex_files diff --git a/androscalpel/src/class.rs b/androscalpel/src/class.rs index 7a26c0a..983a745 100644 --- a/androscalpel/src/class.rs +++ b/androscalpel/src/class.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; +#[cfg(feature = "python")] use pyo3::prelude::*; use crate::{ @@ -12,80 +13,80 @@ use crate::{ use androscalpel_serializer::consts::*; /// Represent an apk -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] pub struct Class { /// Type, format described at /// - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub descriptor: IdType, /// If the class is visible everywhere - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_public: bool, /// If the class is subclassable - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_final: bool, /// If the class is a 'multipy-implementable abstract class' AKA an interface - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_interface: bool, /// If the class is instanciable - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_abstract: bool, /// If the class is not directly defined in the source code - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_synthetic: bool, /// If the class is an annotation - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_annotation: bool, /// If the class is an enum - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_enum: bool, /// Name of the superclass, format described at /// - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub superclass: Option, /// List of the interfaces that class implement, format of the interfaces /// name is discribed at /// - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub interfaces: Vec, /// Name of the source file where this class is defined. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub source_file: Option, /// The static fields - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub static_fields: HashMap, /// The instance fields - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub instance_fields: HashMap, /// The direct (static, private or constructor) methods of the class - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub direct_methods: HashMap, /// The virtual (ie non direct) methods of the class - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub virtual_methods: HashMap, // Do we need to distinguish direct and virtual (all the other) methods? // Maybe overlapping descriptor (same name, class and proto?) /// The annotation related to this class (note: this does not include the /// methods/field/parameters annotations, they are stored in the methods and fields /// structutres) - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub annotations: Vec, } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl Class { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(name: DexString) -> Result { Ok(Self { descriptor: IdType::new(name)?, diff --git a/androscalpel/src/code.rs b/androscalpel/src/code.rs index 93dbee1..0e97829 100644 --- a/androscalpel/src/code.rs +++ b/androscalpel/src/code.rs @@ -4,6 +4,7 @@ use anyhow::anyhow; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; +#[cfg(feature = "python")] use pyo3::prelude::*; use crate::{ @@ -16,26 +17,26 @@ use crate::{ // type TmpHandlerType = (Vec<(IdType, u32)>, Option); /// The code run by a method. -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Code { // TODO: remove and compute this value from code? /// The number of registers used by the code - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub registers_size: u16, // TODO: what does it means? is it computable? /// The number of words of incoming arguments to the method - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub ins_size: u16, // TODO: what does it means? is it computable? /// The number of words of outgoing argument space - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub outs_size: u16, /// The names of the parameters if given - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub parameter_names: Option>>, /// The instructions. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub insns: Vec, } @@ -51,19 +52,19 @@ impl PartialEq for Code { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl Code { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] - #[pyo3(signature = (registers_size, ins_size, outs_size, insns, parameter_names=None))] + #[cfg_attr(feature = "python", new)] + #[cfg_attr(feature = "python", pyo3(signature = (registers_size, ins_size, outs_size, insns, parameter_names=None)))] pub fn new( registers_size: u16, ins_size: u16, diff --git a/androscalpel/src/dex_id.rs b/androscalpel/src/dex_id.rs index a232df7..f9e95ae 100644 --- a/androscalpel/src/dex_id.rs +++ b/androscalpel/src/dex_id.rs @@ -6,6 +6,7 @@ use std::collections::HashSet; use std::hash::Hash; use anyhow::{anyhow, bail, Context}; +#[cfg(feature = "python")] use pyo3::prelude::*; use crate::{scalar::*, DexString, DexValue, Result, Visitable, VisitableMut, Visitor, VisitorMut}; @@ -13,7 +14,7 @@ use androscalpel_serializer::{StringDataItem, Uleb128}; /// The type of a method. The shorty is formated as described in /// -#[pyclass(eq, ord, hash, frozen)] +#[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IdMethodType { /// Type formated as described by @@ -62,18 +63,18 @@ impl PartialOrd for IdMethodType { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl IdMethodType { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(return_type: IdType, parameters: Vec) -> Self { Self { shorty: Self::compute_shorty(&return_type, ¶meters), @@ -100,7 +101,7 @@ impl IdMethodType { /// ) /// ); /// ``` - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_smali(smali_repr: &str) -> Result { if smali_repr.len() < 2 { bail!("'{smali_repr}' is to short to be a prototype"); @@ -229,7 +230,7 @@ impl IdMethodType { /// as described here // Not a clean rust enum because we want to be compatible with python, and maybe support strange // malware edge case? -#[pyclass(eq, ord, hash, frozen)] +#[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct IdType(pub(crate) DexString); @@ -244,20 +245,24 @@ impl VisitableMut for IdType { Ok(Self(v.visit_string(self.0)?)) } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl IdType { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new( - #[pyo3(from_py_with = "crate::dex_string::as_dex_string")] ty: DexString, + #[cfg_attr( + feature = "python", + pyo3(from_py_with = "crate::dex_string::as_dex_string") + )] + ty: DexString, ) -> Result { // TODO: check format let ty = Self(ty); @@ -266,7 +271,7 @@ impl IdType { } /// Return a type from its string representation without checking its format - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn unchecked_new(ty: DexString) -> Self { Self(ty) } @@ -288,7 +293,7 @@ impl IdType { /// IdType::class("androidx/core/util/Predicate") /// ); /// ``` - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_smali(smali_repr: &str) -> Result { Self::new(smali_repr.into()) } @@ -310,7 +315,7 @@ impl IdType { /// IdType::boolean(), /// ]) /// ``` - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn get_list_from_str(type_list: &str) -> Result> { let mut lst = vec![]; let mut chars = type_list.chars(); @@ -364,66 +369,66 @@ impl IdType { } /// Return the void type (for return type) - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn void() -> Self { Self("V".into()) } /// Return the boolean type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn boolean() -> Self { Self("Z".into()) } /// Return the byte type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn byte() -> Self { Self("B".into()) } /// Return the short type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn short() -> Self { Self("S".into()) } /// Return the char type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn char() -> Self { Self("C".into()) } /// Return the int type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn int() -> Self { Self("I".into()) } /// Return the long type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn long() -> Self { Self("J".into()) } /// Return the float type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn float() -> Self { Self("F".into()) } /// Return the double type - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn double() -> Self { Self("D".into()) } /// Return the type for the class of fully qualified name `name` - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn class(name: &str) -> Self { Self(format!("L{name};").into()) } /// Return the type for an array of the specify `type_` - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn array(type_: &IdType) -> Self { let mut ty = type_.clone(); ty.0 .0.utf16_size.0 += 1; @@ -636,18 +641,18 @@ impl SmaliName for IdType { } } -#[pyclass(eq, ord, hash, frozen)] +#[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IdField { /// The name of the field, format described at /// - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub name: DexString, /// The type of the field. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub type_: IdType, /// The class that own the field. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub class_: IdType, } @@ -669,20 +674,24 @@ impl VisitableMut for IdField { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl IdField { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new( - #[pyo3(from_py_with = "crate::dex_string::as_dex_string")] name: DexString, + #[cfg_attr( + feature = "python", + pyo3(from_py_with = "crate::dex_string::as_dex_string") + )] + name: DexString, type_: IdType, class_: IdType, ) -> Self { @@ -709,7 +718,7 @@ impl IdField { /// ) /// ); /// ``` - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_smali(smali_repr: &str) -> Result { let arrow_i = smali_repr.find("->"); if arrow_i.is_none() { @@ -803,17 +812,17 @@ impl SmaliName for IdField { } /// The Id of a method. -#[pyclass(eq, ord, hash, frozen)] +#[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IdMethod { /// The class containing the method. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub class_: IdType, /// The prototype (aka type or signature) of the method. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub proto: IdMethodType, /// The name of the method. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub name: DexString, } @@ -835,20 +844,24 @@ impl VisitableMut for IdMethod { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl IdMethod { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new( - #[pyo3(from_py_with = "crate::dex_string::as_dex_string")] name: DexString, + #[cfg_attr( + feature = "python", + pyo3(from_py_with = "crate::dex_string::as_dex_string") + )] + name: DexString, proto: IdMethodType, class_: IdType, ) -> Self { @@ -884,7 +897,7 @@ impl IdMethod { /// ) /// ); /// ``` - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_smali(smali_repr: &str) -> Result { let arrow_i = smali_repr.find("->"); if arrow_i.is_none() { @@ -998,7 +1011,7 @@ impl SmaliName for IdMethod { } } -#[pyclass(eq, ord, hash, frozen)] +#[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))] #[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct IdEnum(pub IdField); @@ -1014,18 +1027,18 @@ impl VisitableMut for IdEnum { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl IdEnum { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: IdField) -> Self { Self(val) } diff --git a/androscalpel/src/dex_string.rs b/androscalpel/src/dex_string.rs index 080a2aa..26d47c9 100644 --- a/androscalpel/src/dex_string.rs +++ b/androscalpel/src/dex_string.rs @@ -1,13 +1,13 @@ use crate::{Result, Visitable, VisitableMut, Visitor, VisitorMut}; -use pyo3::exceptions::PyTypeError; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::cmp::{Ord, PartialOrd}; use std::collections::HashSet; use std::hash::Hash; -use pyo3::prelude::*; +#[cfg(feature = "python")] +use pyo3::{exceptions::PyTypeError, prelude::*}; -#[pyclass(eq, ord, frozen, hash)] +#[cfg_attr(feature = "python", pyclass(eq, ord, frozen, hash))] #[derive(Clone, PartialEq, Eq, Ord, PartialOrd)] pub struct DexString(pub androscalpel_serializer::StringDataItem); @@ -149,6 +149,7 @@ impl Hash for DexString { } } +#[cfg(feature = "python")] pub fn as_dex_string(obj: &Bound<'_, PyAny>) -> PyResult { if let Ok(string) = DexString::extract_bound(obj) { Ok(string) @@ -162,18 +163,18 @@ pub fn as_dex_string(obj: &Bound<'_, PyAny>) -> PyResult { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexString { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(s: &str) -> Self { s.into() } diff --git a/androscalpel/src/field.rs b/androscalpel/src/field.rs index 1bc4962..7dc94ea 100644 --- a/androscalpel/src/field.rs +++ b/androscalpel/src/field.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; +#[cfg(feature = "python")] use pyo3::prelude::*; use crate::{ @@ -12,45 +13,45 @@ use crate::{ use androscalpel_serializer::consts::*; /// Represent a field. -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct Field { /// The structure used to reference this field. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub descriptor: IdField, /// The field visibility - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub visibility: FieldVisibility, /// If the field is defined for the class globally - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_static: bool, /// If the field is immutable after construction - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_final: bool, /// For thread safety - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_volatile: bool, /// If the field should **not** be saved by default serialization - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_transient: bool, /// If the field is not defined in the source code - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_synthetic: bool, /// If the field is an enumerated value - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_enum: bool, /// The default value of this field pub value: Option, /// The annotations for this field - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub annotations: Vec, /// Hidden Api data. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub hiddenapi: Option, } /// Represent the visibility of a field -#[pyclass(eq, eq_int)] +#[cfg_attr(feature = "python", pyclass(eq, eq_int))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub enum FieldVisibility { Public, @@ -59,18 +60,18 @@ pub enum FieldVisibility { None_, // Actually quite common } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl Field { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(descriptor: IdField) -> Self { Self { descriptor, @@ -124,12 +125,14 @@ impl Field { } /// Return the value as a python object + #[cfg(feature = "python")] #[getter] pub fn get_value(&self) -> Option { self.value.clone() } /// Set the value from a python object + #[cfg(feature = "python")] #[setter] pub fn set_value(&mut self, ob: &Bound<'_, PyAny>) -> PyResult<()> { self.value = Some(ob.extract()?); diff --git a/androscalpel/src/hiddenapi.rs b/androscalpel/src/hiddenapi.rs index e8ac6f3..eb25a5e 100644 --- a/androscalpel/src/hiddenapi.rs +++ b/androscalpel/src/hiddenapi.rs @@ -2,10 +2,11 @@ use crate::{Result, Visitable, VisitableMut, Visitor, VisitorMut}; use log::warn; +#[cfg(feature = "python")] use pyo3::prelude::*; use serde::{Deserialize, Serialize}; -#[pyclass] +#[cfg_attr(feature = "python", pyclass)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)] pub struct HiddenApiData { pub permission: HiddenApiPermission, @@ -56,7 +57,7 @@ impl VisitableMut for HiddenApiData { } } -#[pyclass] +#[cfg_attr(feature = "python", pyclass)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)] pub enum HiddenApiPermission { /// Interfaces that can be freely used and are supported as @@ -147,7 +148,7 @@ impl From for androscalpel_serializer::HiddenApiValue { } } -#[pyclass] +#[cfg_attr(feature = "python", pyclass)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)] pub struct HiddenApiDomain { pub is_core_platform_api: bool, diff --git a/androscalpel/src/instructions.rs b/androscalpel/src/instructions.rs index bcebdc3..4b72558 100644 --- a/androscalpel/src/instructions.rs +++ b/androscalpel/src/instructions.rs @@ -15,6 +15,7 @@ use androscalpel_serializer::Instruction as InsFormat; use androscalpel_serializer::Serializable; use anyhow::{anyhow, bail}; +#[cfg(feature = "python")] use pyo3::prelude::*; use std::collections::{HashMap, HashSet}; @@ -31,7 +32,7 @@ const I32_MIN_AS_I64: i64 = i32::MIN as i64; const I32_MAX_AS_I64: i64 = i32::MAX as i64; const U16_MAX_AS_USIZE: usize = u16::MAX as usize; -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub enum Instruction { /// Waste a cycle. @@ -2094,13 +2095,13 @@ macro_rules! raw_ins_invoke { }}; } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl Instruction { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } @@ -6596,31 +6597,31 @@ impl Instruction { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct CallSite { - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub method_handle: MethodHandle, - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub name: DexString, - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub type_: IdMethodType, - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub args: Vec, } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl CallSite { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new( method_handle: MethodHandle, name: DexString, diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index 41c5c75..9d1b2f3 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -3,6 +3,7 @@ // python, TryInto should be prefered use anyhow::Result; +#[cfg(feature = "python")] use pyo3::prelude::*; pub mod annotation; @@ -18,6 +19,7 @@ pub mod hiddenapi; pub mod instructions; pub mod method; pub mod method_handle; +#[cfg(feature = "python")] pub mod py_utils; pub mod scalar; pub mod value; @@ -44,6 +46,7 @@ pub use visitor::*; mod tests; /// Androscalpel. +#[cfg(feature = "python")] #[pymodule] fn androscalpel(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { pyo3_log::init(); @@ -90,6 +93,7 @@ fn androscalpel(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { } /// Dalvik opcode for Androscalpel. +#[cfg(feature = "python")] fn androscalpel_ins(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; diff --git a/androscalpel/src/method.rs b/androscalpel/src/method.rs index fd55307..e586849 100644 --- a/androscalpel/src/method.rs +++ b/androscalpel/src/method.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; +#[cfg(feature = "python")] use pyo3::prelude::*; use crate::{ @@ -12,67 +13,67 @@ use crate::{ use androscalpel_serializer::consts::*; /// Represent a method. -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] pub struct Method { /// The structure used to reference this method. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub descriptor: IdMethod, /// The field visibility. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub visibility: MethodVisibility, /// Static methods do not take this in argument. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_static: bool, /// Final methods are not averridable. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_final: bool, /// Synchronized method automatically acquire their associated lock around call. /// Can only be set in native method, (`[Self::is_native] = true`). - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_synchronized: bool, /// Bridge are automatically added by the compiler as a type-safe bridge. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_bridge: bool, /// If the last argument should be treated as a "rest" argument by compiler /// (for method of variable number of argument). - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_varargs: bool, /// If the method is a native method. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_native: bool, /// Abstract methods are not implemented by the class. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_abstract: bool, /// If the method must use strict rules for floating point arithmetic. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_strictfp: bool, /// Synthetic method are not directly defined in the source code. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_synthetic: bool, /// If the method is a constructor. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_constructor: bool, /// If the method is declared as synchronize (just indicatif) - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub is_declared_syncrhonized: bool, /// The annotations for this method - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub annotations: Vec, /// The annotations for the parameters of this method method - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub parameters_annotations: Vec>, /// Hidden Api data. - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub hiddenapi: Option, /// The code of the method - #[pyo3(get)] + #[cfg_attr(feature = "python", pyo3(get))] pub code: Option, } /// Represent the visibility of a field -#[pyclass(eq, eq_int)] +#[cfg_attr(feature = "python", pyclass(eq, eq_int))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub enum MethodVisibility { Public, @@ -81,18 +82,18 @@ pub enum MethodVisibility { None_, // Actually quite common } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl Method { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(descriptor: IdMethod) -> Self { // TODO: take code option as arg and set the default flags accordingly Self { diff --git a/androscalpel/src/method_handle.rs b/androscalpel/src/method_handle.rs index e2ed216..f931afc 100644 --- a/androscalpel/src/method_handle.rs +++ b/androscalpel/src/method_handle.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::hash::Hash; +#[cfg(feature = "python")] use pyo3::prelude::*; use crate::dex_id::*; @@ -13,7 +14,7 @@ use crate::{ }; /// The structure use to reference a method invocation. -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] pub enum MethodHandle { StaticPut { field: IdField }, @@ -78,13 +79,13 @@ impl VisitableMut for MethodHandle { } } -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl MethodHandle { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } diff --git a/androscalpel/src/scalar.rs b/androscalpel/src/scalar.rs index 849c24a..621b2e0 100644 --- a/androscalpel/src/scalar.rs +++ b/androscalpel/src/scalar.rs @@ -8,23 +8,25 @@ use crate::{ DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle, Visitable, VisitableMut, Visitor, VisitorMut, }; +#[cfg(feature = "python")] use pyo3::prelude::*; -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct DexByte(pub i8); -#[pymethods] + +#[cfg_attr(feature = "python", pymethods)] impl DexByte { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: i8) -> Self { Self(val) } @@ -42,21 +44,21 @@ impl DexByte { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct DexShort(pub i16); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexShort { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: i16) -> Self { Self(val) } @@ -74,21 +76,21 @@ impl DexShort { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct DexChar(pub u16); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexChar { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: u16) -> Self { Self(val) } @@ -106,21 +108,21 @@ impl DexChar { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct DexInt(pub i32); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexInt { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: i32) -> Self { Self(val) } @@ -138,21 +140,21 @@ impl DexInt { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct DexLong(pub i64); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexLong { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: i64) -> Self { Self(val) } @@ -170,21 +172,21 @@ impl DexLong { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] pub struct DexFloat(pub f32); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexFloat { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: f32) -> Self { Self(val) } @@ -202,21 +204,21 @@ impl DexFloat { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] pub struct DexDouble(pub f64); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexDouble { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: f64) -> Self { Self(val) } @@ -235,21 +237,21 @@ impl DexDouble { } /* DexString is already define in lib.rs, TODO: move the version in lib.rs here -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DexString(pub u32); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexString { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: u32) -> Self { Self(val) } @@ -268,21 +270,21 @@ impl DexString { } */ -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct DexNull; -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexNull { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn _new() -> Self { Self } @@ -296,21 +298,21 @@ impl DexNull { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct DexBoolean(pub bool); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexBoolean { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn new(val: bool) -> Self { Self(val) } @@ -328,21 +330,21 @@ impl DexBoolean { } } -#[pyclass(eq)] +#[cfg_attr(feature = "python", pyclass(eq))] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct DexArray(pub Vec); -#[pymethods] +#[cfg_attr(feature = "python", pymethods)] impl DexArray { pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } - #[staticmethod] + #[cfg_attr(feature = "python", staticmethod)] pub fn from_json(json: &str) -> Result { Ok(serde_json::from_str(json)?) } - #[new] + #[cfg_attr(feature = "python", new)] pub fn _new(arr: Vec) -> Self { Self(arr) } diff --git a/androscalpel/src/value.rs b/androscalpel/src/value.rs index e25d857..b63c051 100644 --- a/androscalpel/src/value.rs +++ b/androscalpel/src/value.rs @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; -use pyo3::exceptions::PyTypeError; -use pyo3::prelude::*; +#[cfg(feature = "python")] +use pyo3::{exceptions::PyTypeError, prelude::*}; use crate::{ dex_id::*, scalar::*, DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut, @@ -83,6 +83,7 @@ impl VisitableMut for DexValue { } } +#[cfg(feature = "python")] impl<'source> FromPyObject<'source> for DexValue { fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { if let Ok(val) = DexByte::extract_bound(ob) { @@ -305,7 +306,7 @@ impl DexValue { } } } - +#[cfg(feature = "python")] impl<'py> IntoPyObject<'py> for DexValue { type Target = PyAny; type Output = Bound<'py, Self::Target>;