mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Merge pull request #3613 from youknowone/pystructseq-fromobj
derive(TryIntoPyStructSequence)
This commit is contained in:
13 files changed
+164
-97
No files matched your search
@@ -102,6 +102,14 @@ pub fn pystruct_sequence(input: proc_macro::TokenStream) -> proc_macro::TokenStr
|
||||
result_to_tokens(pystructseq::impl_pystruct_sequence(input))
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryIntoPyStructSequence)]
|
||||
pub fn pystruct_sequence_try_from_object(
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
result_to_tokens(pystructseq::impl_pystruct_sequence_try_from_object(input))
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn py_compile(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
result_to_tokens(compile_bytecode::impl_py_compile(input.into()))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Result};
|
||||
use syn::{DeriveInput, Ident, Result};
|
||||
|
||||
pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result<TokenStream> {
|
||||
fn field_names(input: &DeriveInput) -> Result<Vec<&Ident>> {
|
||||
let fields = if let syn::Data::Struct(ref struc) = input.data {
|
||||
&struc.fields
|
||||
} else {
|
||||
@@ -24,9 +24,14 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result<TokenStream>
|
||||
),
|
||||
};
|
||||
|
||||
Ok(field_names)
|
||||
}
|
||||
|
||||
pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result<TokenStream> {
|
||||
let field_names = field_names(&input)?;
|
||||
let ty = &input.ident;
|
||||
let ret = quote! {
|
||||
impl ::rustpython_vm::PyStructSequence for #ty {
|
||||
impl ::rustpython_vm::types::PyStructSequence for #ty {
|
||||
const FIELD_NAMES: &'static [&'static str] = &[#(stringify!(#field_names)),*];
|
||||
fn into_tuple(self, vm: &::rustpython_vm::VirtualMachine) -> ::rustpython_vm::builtins::PyTuple {
|
||||
let items = vec![#(::rustpython_vm::convert::ToPyObject::to_pyobject(
|
||||
@@ -38,7 +43,26 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result<TokenStream>
|
||||
}
|
||||
impl ::rustpython_vm::convert::ToPyObject for #ty {
|
||||
fn to_pyobject(self, vm: &::rustpython_vm::VirtualMachine) -> ::rustpython_vm::PyObjectRef {
|
||||
::rustpython_vm::PyStructSequence::into_struct_sequence(self, vm).into()
|
||||
::rustpython_vm::types::PyStructSequence::into_struct_sequence(self, vm).into()
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub(crate) fn impl_pystruct_sequence_try_from_object(input: DeriveInput) -> Result<TokenStream> {
|
||||
let field_names = field_names(&input)?;
|
||||
let ty = &input.ident;
|
||||
let ret = quote! {
|
||||
impl ::rustpython_vm::TryFromObject for #ty {
|
||||
fn try_from_object(vm: &::rustpython_vm::VirtualMachine, seq: ::rustpython_vm::PyObjectRef) -> ::rustpython_vm::PyResult<Self> {
|
||||
const LEN: usize = #ty::FIELD_NAMES.len();
|
||||
let seq = Self::try_elements_from::<LEN>(seq, vm)?;
|
||||
// TODO: this is possible to be written without iterator
|
||||
let mut iter = seq.into_iter();
|
||||
Ok(Self {#(
|
||||
#field_names: iter.next().unwrap().clone().try_into_value(vm)?
|
||||
),*})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,8 @@ mod resource {
|
||||
use crate::vm::{
|
||||
convert::{ToPyException, ToPyObject},
|
||||
stdlib::os,
|
||||
PyObject, PyObjectRef, PyResult, PyStructSequence, TryFromBorrowedObject, VirtualMachine,
|
||||
types::PyStructSequence,
|
||||
PyObject, PyObjectRef, PyResult, TryFromBorrowedObject, VirtualMachine,
|
||||
};
|
||||
use std::{io, mem};
|
||||
|
||||
|
||||
@@ -77,6 +77,12 @@ impl PyStrKindData {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromBorrowedObject for String {
|
||||
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
|
||||
obj.try_value_with(|pystr: &PyStr| Ok(pystr.as_str().to_owned()), vm)
|
||||
}
|
||||
}
|
||||
|
||||
/// str(object='') -> str
|
||||
/// str(bytes_or_buffer[, encoding[, errors]]) -> str
|
||||
///
|
||||
|
||||
+3
-3
@@ -88,12 +88,12 @@ mod pyobject {
|
||||
// pub use self::Executor;
|
||||
pub use self::convert::{TryFromBorrowedObject, TryFromObject};
|
||||
// pyobject items
|
||||
pub use self::pyobject::{
|
||||
AsObject, PyContext, PyMethod, PyRefExact, PyResult, PyStructSequence, PyValue,
|
||||
};
|
||||
pub use self::pyobject::{AsObject, PyContext, PyMethod, PyRefExact, PyResult, PyValue};
|
||||
// pyobjectrc items
|
||||
pub use self::pyobject::{PyObject, PyObjectRef, PyObjectView, PyObjectWeak, PyRef, PyWeakRef};
|
||||
pub use self::types::PyStructSequence;
|
||||
pub use self::vm::{InitParameter, Interpreter, PySettings, VirtualMachine};
|
||||
|
||||
pub use rustpython_bytecode as bytecode;
|
||||
pub use rustpython_common as common;
|
||||
#[cfg(feature = "rustpython-compiler")]
|
||||
|
||||
+13
-59
@@ -622,66 +622,20 @@ pub trait PyObjectPayload: Any + fmt::Debug + PyThreadingConstraint + 'static {}
|
||||
|
||||
impl<T: PyValue + 'static> PyObjectPayload for T {}
|
||||
|
||||
#[pyimpl]
|
||||
pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
|
||||
const FIELD_NAMES: &'static [&'static str];
|
||||
pub trait PyObjectWrap
|
||||
where
|
||||
Self: AsObject,
|
||||
{
|
||||
fn into_object(self) -> PyObjectRef;
|
||||
}
|
||||
|
||||
fn into_tuple(self, vm: &VirtualMachine) -> PyTuple;
|
||||
|
||||
fn into_struct_sequence(self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
self.into_tuple(vm)
|
||||
.into_ref_with_type(vm, Self::static_type().clone())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyRef<PyTuple>, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let format_field = |(value, name): (&PyObjectRef, _)| {
|
||||
let s = value.repr(vm)?;
|
||||
Ok(format!("{}={}", name, s))
|
||||
};
|
||||
let (body, suffix) =
|
||||
if let Some(_guard) = rustpython_vm::vm::ReprGuard::enter(vm, zelf.as_object()) {
|
||||
if Self::FIELD_NAMES.len() == 1 {
|
||||
let value = zelf.as_slice().first().unwrap();
|
||||
let formatted = format_field((value, Self::FIELD_NAMES[0]))?;
|
||||
(formatted, ",")
|
||||
} else {
|
||||
let fields: PyResult<Vec<_>> = zelf
|
||||
.as_slice()
|
||||
.iter()
|
||||
.zip(Self::FIELD_NAMES.iter().copied())
|
||||
.map(format_field)
|
||||
.collect();
|
||||
(fields?.join(", "), "")
|
||||
}
|
||||
} else {
|
||||
(String::new(), "...")
|
||||
};
|
||||
Ok(format!("{}({}{})", Self::TP_NAME, body, suffix))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn reduce(zelf: PyRef<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
|
||||
vm.new_tuple((
|
||||
zelf.class().clone(),
|
||||
(vm.ctx.new_tuple(zelf.as_slice().to_vec()),),
|
||||
))
|
||||
}
|
||||
|
||||
#[extend_class]
|
||||
fn extend_pyclass(ctx: &PyContext, class: &PyTypeRef) {
|
||||
for (i, &name) in Self::FIELD_NAMES.iter().enumerate() {
|
||||
// cast i to a u8 so there's less to store in the getter closure.
|
||||
// Hopefully there's not struct sequences with >=256 elements :P
|
||||
let i = i as u8;
|
||||
class.set_str_attr(
|
||||
name,
|
||||
ctx.new_readonly_getset(name, class.clone(), move |zelf: &PyTuple| {
|
||||
zelf.fast_getitem(i.into())
|
||||
}),
|
||||
);
|
||||
}
|
||||
impl<T> From<T> for PyObjectRef
|
||||
where
|
||||
T: PyObjectWrap,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn from(py_ref: T) -> Self {
|
||||
py_ref.into_object()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -413,10 +413,10 @@ pub(super) mod _os {
|
||||
function::{ArgBytesLike, FuncArgs, OptionalArg},
|
||||
protocol::PyIterReturn,
|
||||
suppress_iph,
|
||||
types::{IterNext, IterNextIterable},
|
||||
types::{IterNext, IterNextIterable, PyStructSequence},
|
||||
utils::Either,
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
AsObject, PyObjectRef, PyRef, PyResult, PyStructSequence, PyValue, TryFromObject,
|
||||
AsObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use itertools::Itertools;
|
||||
|
||||
@@ -5,7 +5,8 @@ mod pwd {
|
||||
use crate::{
|
||||
builtins::{PyIntRef, PyStrRef},
|
||||
convert::{ToPyException, ToPyObject},
|
||||
AsObject, PyObjectRef, PyResult, PyStructSequence, VirtualMachine,
|
||||
types::PyStructSequence,
|
||||
AsObject, PyObjectRef, PyResult, VirtualMachine,
|
||||
};
|
||||
use nix::unistd::{self, User};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
@@ -13,9 +13,10 @@ mod sys {
|
||||
frame::FrameRef,
|
||||
function::{FuncArgs, OptionalArg, PosArgs},
|
||||
stdlib::builtins,
|
||||
types::PyStructSequence,
|
||||
version,
|
||||
vm::{PySettings, VirtualMachine},
|
||||
PyObjectRef, PyRef, PyRefExact, PyResult, PyStructSequence,
|
||||
PyObjectRef, PyRef, PyRefExact, PyResult,
|
||||
};
|
||||
use num_traits::ToPrimitive;
|
||||
use std::{env, mem, path};
|
||||
|
||||
+3
-25
@@ -21,8 +21,9 @@ mod time {
|
||||
use crate::{
|
||||
builtins::{PyStrRef, PyTypeRef},
|
||||
function::{FuncArgs, OptionalArg},
|
||||
types::PyStructSequence,
|
||||
utils::Either,
|
||||
PyObjectRef, PyResult, PyStructSequence, TryFromObject, VirtualMachine,
|
||||
PyObjectRef, PyResult, TryFromObject, VirtualMachine,
|
||||
};
|
||||
use chrono::{
|
||||
naive::{NaiveDate, NaiveDateTime, NaiveTime},
|
||||
@@ -315,7 +316,7 @@ mod time {
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(name = "struct_time")]
|
||||
#[derive(PyStructSequence)]
|
||||
#[derive(PyStructSequence, TryIntoPyStructSequence)]
|
||||
#[allow(dead_code)]
|
||||
struct PyStructTime {
|
||||
tm_year: PyObjectRef,
|
||||
@@ -375,29 +376,6 @@ mod time {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for PyStructTime {
|
||||
fn try_from_object(vm: &VirtualMachine, seq: PyObjectRef) -> PyResult<Self> {
|
||||
let seq: Vec<_> = seq.try_to_value(vm)?;
|
||||
if seq.len() != 9 {
|
||||
return Err(
|
||||
vm.new_type_error("time.struct_time() takes a sequence of length 9".to_owned())
|
||||
);
|
||||
}
|
||||
let mut i = seq.into_iter();
|
||||
Ok(PyStructTime {
|
||||
tm_year: i.next().unwrap(),
|
||||
tm_mon: i.next().unwrap(),
|
||||
tm_mday: i.next().unwrap(),
|
||||
tm_hour: i.next().unwrap(),
|
||||
tm_min: i.next().unwrap(),
|
||||
tm_sec: i.next().unwrap(),
|
||||
tm_wday: i.next().unwrap(),
|
||||
tm_yday: i.next().unwrap(),
|
||||
tm_isdst: i.next().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(unix)]
|
||||
use super::unix::*;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
mod slot;
|
||||
mod structseq;
|
||||
mod zoo;
|
||||
|
||||
pub use slot::*;
|
||||
pub use structseq::PyStructSequence;
|
||||
pub(crate) use zoo::TypeZoo;
|
||||
@@ -0,0 +1,92 @@
|
||||
use crate::{
|
||||
builtins::{PyTuple, PyTupleRef, PyTypeRef},
|
||||
pyclass::{PyClassImpl, StaticType},
|
||||
pyobject::PyContext,
|
||||
AsObject, PyObjectRef, PyRef, PyResult, PyValue, VirtualMachine,
|
||||
};
|
||||
|
||||
#[pyimpl]
|
||||
pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
|
||||
const FIELD_NAMES: &'static [&'static str];
|
||||
|
||||
fn into_tuple(self, vm: &VirtualMachine) -> PyTuple;
|
||||
|
||||
fn into_struct_sequence(self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
self.into_tuple(vm)
|
||||
.into_ref_with_type(vm, Self::static_type().clone())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn try_elements_from<const FIELD_LEN: usize>(
|
||||
obj: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<[PyObjectRef; FIELD_LEN]> {
|
||||
let typ = Self::static_type();
|
||||
// if !obj.fast_isinstance(typ) {
|
||||
// return Err(vm.new_type_error(format!(
|
||||
// "{} is not a subclass of {}",
|
||||
// obj.class().name(),
|
||||
// typ.name(),
|
||||
// )));
|
||||
// }
|
||||
let seq: Vec<PyObjectRef> = obj.try_into_value(vm)?;
|
||||
let seq: [PyObjectRef; FIELD_LEN] = seq.try_into().map_err(|_| {
|
||||
vm.new_type_error(format!(
|
||||
"{} takes a sequence of length {}",
|
||||
typ.name(),
|
||||
FIELD_LEN
|
||||
))
|
||||
})?;
|
||||
Ok(seq)
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyRef<PyTuple>, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let format_field = |(value, name): (&PyObjectRef, _)| {
|
||||
let s = value.repr(vm)?;
|
||||
Ok(format!("{}={}", name, s))
|
||||
};
|
||||
let (body, suffix) =
|
||||
if let Some(_guard) = rustpython_vm::vm::ReprGuard::enter(vm, zelf.as_object()) {
|
||||
if Self::FIELD_NAMES.len() == 1 {
|
||||
let value = zelf.as_slice().first().unwrap();
|
||||
let formatted = format_field((value, Self::FIELD_NAMES[0]))?;
|
||||
(formatted, ",")
|
||||
} else {
|
||||
let fields: PyResult<Vec<_>> = zelf
|
||||
.as_slice()
|
||||
.iter()
|
||||
.zip(Self::FIELD_NAMES.iter().copied())
|
||||
.map(format_field)
|
||||
.collect();
|
||||
(fields?.join(", "), "")
|
||||
}
|
||||
} else {
|
||||
(String::new(), "...")
|
||||
};
|
||||
Ok(format!("{}({}{})", Self::TP_NAME, body, suffix))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn reduce(zelf: PyRef<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
|
||||
vm.new_tuple((
|
||||
zelf.class().clone(),
|
||||
(vm.ctx.new_tuple(zelf.as_slice().to_vec()),),
|
||||
))
|
||||
}
|
||||
|
||||
#[extend_class]
|
||||
fn extend_pyclass(ctx: &PyContext, class: &PyTypeRef) {
|
||||
for (i, &name) in Self::FIELD_NAMES.iter().enumerate() {
|
||||
// cast i to a u8 so there's less to store in the getter closure.
|
||||
// Hopefully there's not struct sequences with >=256 elements :P
|
||||
let i = i as u8;
|
||||
class.set_str_attr(
|
||||
name,
|
||||
ctx.new_readonly_getset(name, class.clone(), move |zelf: &PyTuple| {
|
||||
zelf.fast_getitem(i.into())
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/* Several function to retrieve version information.
|
||||
*/
|
||||
|
||||
use crate::PyStructSequence;
|
||||
use crate::types::PyStructSequence;
|
||||
use chrono::prelude::DateTime;
|
||||
use chrono::Local;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
Reference in new issue
Block a user