put pyo3 away for now

This commit is contained in:
Jean-Marie Mineau 2025-01-24 16:43:30 +01:00
parent ea6ce5d7a1
commit 1c45b9e38b
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
15 changed files with 248 additions and 215 deletions

View file

@ -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"]

View file

@ -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<Self> {
Ok(serde_json::from_str(json)?)
}
@ -122,23 +123,23 @@ impl<V: VisitorMut> VisitableMut<V> 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<DexString, DexValue>, // 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<DexString, DexValue>) -> 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<Self> {
Ok(serde_json::from_str(json)?)
}

View file

@ -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<String, DexFile>, // 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<Self> {
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<Self> {
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<HashMap<String, PyObject>> {
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<Self> {
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

View file

@ -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
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[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
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub superclass: Option<IdType>,
/// List of the interfaces that class implement, format of the interfaces
/// name is discribed at
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub interfaces: Vec<IdType>,
/// Name of the source file where this class is defined.
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub source_file: Option<DexString>,
/// The static fields
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub static_fields: HashMap<IdField, Field>,
/// The instance fields
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub instance_fields: HashMap<IdField, Field>,
/// The direct (static, private or constructor) methods of the class
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub direct_methods: HashMap<IdMethod, Method>,
/// The virtual (ie non direct) methods of the class
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub virtual_methods: HashMap<IdMethod, Method>,
// 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<DexAnnotationItem>,
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl Class {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?)
}
#[new]
#[cfg_attr(feature = "python", new)]
pub fn new(name: DexString) -> Result<Self> {
Ok(Self {
descriptor: IdType::new(name)?,

View file

@ -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<u32>);
/// 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<Vec<Option<DexString>>>,
/// The instructions.
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub insns: Vec<Instruction>,
}
@ -51,19 +52,19 @@ impl PartialEq for Code {
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl Code {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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,

View file

@ -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
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
#[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 <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
@ -62,18 +63,18 @@ impl PartialOrd for IdMethodType {
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl IdMethodType {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?)
}
#[new]
#[cfg_attr(feature = "python", new)]
pub fn new(return_type: IdType, parameters: Vec<IdType>) -> Self {
Self {
shorty: Self::compute_shorty(&return_type, &parameters),
@ -100,7 +101,7 @@ impl IdMethodType {
/// )
/// );
/// ```
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_smali(smali_repr: &str) -> Result<Self> {
if smali_repr.len() < 2 {
bail!("'{smali_repr}' is to short to be a prototype");
@ -229,7 +230,7 @@ impl IdMethodType {
/// as described here <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
// 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<V: VisitorMut> VisitableMut<V> for IdType {
Ok(Self(v.visit_string(self.0)?))
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl IdType {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<Self> {
// 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> {
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<Vec<Self>> {
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
/// <https://source.android.com/docs/core/runtime/dex-format#membername>
#[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<V: VisitorMut> VisitableMut<V> for IdField {
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl IdField {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<Self> {
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<V: VisitorMut> VisitableMut<V> for IdMethod {
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl IdMethod {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<Self> {
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<V: VisitorMut> VisitableMut<V> for IdEnum {
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl IdEnum {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?)
}
#[new]
#[cfg_attr(feature = "python", new)]
pub fn new(val: IdField) -> Self {
Self(val)
}

View file

@ -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<DexString> {
if let Ok(string) = DexString::extract_bound(obj) {
Ok(string)
@ -162,18 +163,18 @@ pub fn as_dex_string(obj: &Bound<'_, PyAny>) -> PyResult<DexString> {
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl DexString {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?)
}
#[new]
#[cfg_attr(feature = "python", new)]
pub fn new(s: &str) -> Self {
s.into()
}

View file

@ -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<DexValue>,
/// The annotations for this field
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub annotations: Vec<DexAnnotationItem>,
/// Hidden Api data.
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub hiddenapi: Option<HiddenApiData>,
}
/// 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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<DexValue> {
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()?);

View file

@ -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<V: VisitorMut> VisitableMut<V> 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<HiddenApiPermission> 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,

View file

@ -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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<DexValue>,
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl CallSite {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?)
}
#[new]
#[cfg_attr(feature = "python", new)]
pub fn new(
method_handle: MethodHandle,
name: DexString,

View file

@ -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::<ins::CallSite>()?;
m.add_class::<ins::Instruction>()?;

View file

@ -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<DexAnnotationItem>,
/// The annotations for the parameters of this method method
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub parameters_annotations: Vec<Vec<DexAnnotationItem>>,
/// Hidden Api data.
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub hiddenapi: Option<HiddenApiData>,
/// The code of the method
#[pyo3(get)]
#[cfg_attr(feature = "python", pyo3(get))]
pub code: Option<Code>,
}
/// 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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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 {

View file

@ -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<V: VisitorMut> VisitableMut<V> for MethodHandle {
}
}
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl MethodHandle {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?)
}

View file

@ -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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
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<DexValue>);
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl DexArray {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
#[staticmethod]
#[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?)
}
#[new]
#[cfg_attr(feature = "python", new)]
pub fn _new(arr: Vec<DexValue>) -> Self {
Self(arr)
}

View file

@ -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<V: VisitorMut> VisitableMut<V> for DexValue {
}
}
#[cfg(feature = "python")]
impl<'source> FromPyObject<'source> for DexValue {
fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult<Self> {
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>;