From bf18e281ed52643f4b3c0eed9a8ca0621a5401f9 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Fri, 8 Apr 2022 19:24:43 +0900 Subject: [PATCH 1/6] derive macro for TryFromObject for PyStructSequence --- derive/src/lib.rs | 8 ++++++++ derive/src/pystructseq.rs | 29 +++++++++++++++++++++++++++-- vm/src/builtins/pystr.rs | 6 ++++++ vm/src/pyobject.rs | 21 +++++++++++++++++++++ vm/src/stdlib/time.rs | 25 +------------------------ 5 files changed, 63 insertions(+), 26 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 0443e177c..c99a5874d 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -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())) diff --git a/derive/src/pystructseq.rs b/derive/src/pystructseq.rs index 08cbe6980..69f9e10e0 100644 --- a/derive/src/pystructseq.rs +++ b/derive/src/pystructseq.rs @@ -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 { +fn field_names(input: &DeriveInput) -> Result> { let fields = if let syn::Data::Struct(ref struc) = input.data { &struc.fields } else { @@ -24,9 +24,17 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result ), }; + Ok(field_names) +} + +pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result { + let field_names = field_names(&input)?; let ty = &input.ident; let ret = quote! { impl ::rustpython_vm::PyStructSequence for #ty { + const FIELD_LEN: usize = [#( + stringify!(#field_names) + ),*].len(); 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( @@ -44,3 +52,20 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result }; Ok(ret) } + +pub(crate) fn impl_pystruct_sequence_try_from_object(input: DeriveInput) -> Result { + 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 { + let seq = Self::try_elements_from(seq, vm)?; + let mut iter = seq.into_iter(); + Ok(Self {#( + #field_names: iter.next().unwrap().clone().try_into_value(vm)? + ),*}) + } + } + }; + Ok(ret) +} diff --git a/vm/src/builtins/pystr.rs b/vm/src/builtins/pystr.rs index 26f4a0f1f..1c9d0303f 100644 --- a/vm/src/builtins/pystr.rs +++ b/vm/src/builtins/pystr.rs @@ -77,6 +77,12 @@ impl PyStrKindData { } } +impl TryFromBorrowedObject for String { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult { + obj.try_value_with(|pystr: &PyStr| Ok(pystr.as_str().to_owned()), vm) + } +} + /// str(object='') -> str /// str(bytes_or_buffer[, encoding[, errors]]) -> str /// diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index e3ce56451..e823fcda6 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -624,6 +624,7 @@ impl PyObjectPayload for T {} #[pyimpl] pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { + const FIELD_LEN: usize; const FIELD_NAMES: &'static [&'static str]; fn into_tuple(self, vm: &VirtualMachine) -> PyTuple; @@ -634,6 +635,26 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { .unwrap() } + fn try_elements_from(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult> { + 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 = obj.try_into_value(vm)?; + if seq.len() != Self::FIELD_LEN { + return Err(vm.new_type_error(format!( + "{} takes a sequence of length {}", + typ.name(), + Self::FIELD_LEN + ))); + } + Ok(seq) + } + #[pymethod(magic)] fn repr(zelf: PyRef, vm: &VirtualMachine) -> PyResult { let format_field = |(value, name): (&PyObjectRef, _)| { diff --git a/vm/src/stdlib/time.rs b/vm/src/stdlib/time.rs index 9c7cf7493..91a958328 100644 --- a/vm/src/stdlib/time.rs +++ b/vm/src/stdlib/time.rs @@ -315,7 +315,7 @@ mod time { #[pyattr] #[pyclass(name = "struct_time")] - #[derive(PyStructSequence)] + #[derive(PyStructSequence, TryIntoPyStructSequence)] #[allow(dead_code)] struct PyStructTime { tm_year: PyObjectRef, @@ -375,29 +375,6 @@ mod time { } } - impl TryFromObject for PyStructTime { - fn try_from_object(vm: &VirtualMachine, seq: PyObjectRef) -> PyResult { - 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::*; From 4f531d1c6b0313ace0b9402530edd002a207f374 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 19 Apr 2022 15:14:17 +0900 Subject: [PATCH 2/6] remove FIELD_LEN --- derive/src/pystructseq.rs | 3 --- vm/src/pyobject.rs | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/derive/src/pystructseq.rs b/derive/src/pystructseq.rs index 69f9e10e0..7e3b355fc 100644 --- a/derive/src/pystructseq.rs +++ b/derive/src/pystructseq.rs @@ -32,9 +32,6 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result let ty = &input.ident; let ret = quote! { impl ::rustpython_vm::PyStructSequence for #ty { - const FIELD_LEN: usize = [#( - stringify!(#field_names) - ),*].len(); 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( diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index e823fcda6..22f8771d4 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -624,7 +624,6 @@ impl PyObjectPayload for T {} #[pyimpl] pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { - const FIELD_LEN: usize; const FIELD_NAMES: &'static [&'static str]; fn into_tuple(self, vm: &VirtualMachine) -> PyTuple; @@ -645,11 +644,11 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { ))); } let seq: Vec = obj.try_into_value(vm)?; - if seq.len() != Self::FIELD_LEN { + if seq.len() != Self::FIELD_NAMES.len() { return Err(vm.new_type_error(format!( "{} takes a sequence of length {}", typ.name(), - Self::FIELD_LEN + Self::FIELD_NAMES.len() ))); } Ok(seq) From 6de62d937eb23c076392c1b355a8de4040b7ce0f Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Mon, 18 Apr 2022 01:23:36 +0900 Subject: [PATCH 3/6] module for PyStructSequence --- derive/src/pystructseq.rs | 4 +- vm/src/lib.rs | 6 +-- vm/src/pyobject.rs | 92 ++++++--------------------------------- vm/src/types/mod.rs | 2 + vm/src/types/structseq.rs | 89 +++++++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 83 deletions(-) create mode 100644 vm/src/types/structseq.rs diff --git a/derive/src/pystructseq.rs b/derive/src/pystructseq.rs index 7e3b355fc..535b31fcd 100644 --- a/derive/src/pystructseq.rs +++ b/derive/src/pystructseq.rs @@ -56,7 +56,9 @@ pub(crate) fn impl_pystruct_sequence_try_from_object(input: DeriveInput) -> Resu let ret = quote! { impl ::rustpython_vm::TryFromObject for #ty { fn try_from_object(vm: &::rustpython_vm::VirtualMachine, seq: ::rustpython_vm::PyObjectRef) -> ::rustpython_vm::PyResult { - let seq = Self::try_elements_from(seq, vm)?; + const LEN: usize = #ty::FIELD_NAMES.len(); + let seq = Self::try_elements_from::(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)? diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 862aba2f4..8fbdaa623 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -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")] diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 22f8771d4..0385283b1 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -622,86 +622,20 @@ pub trait PyObjectPayload: Any + fmt::Debug + PyThreadingConstraint + 'static {} impl 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() - } - - fn try_elements_from(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - 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 = obj.try_into_value(vm)?; - if seq.len() != Self::FIELD_NAMES.len() { - return Err(vm.new_type_error(format!( - "{} takes a sequence of length {}", - typ.name(), - Self::FIELD_NAMES.len() - ))); - } - Ok(seq) - } - - #[pymethod(magic)] - fn repr(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - 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> = 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, 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 From for PyObjectRef +where + T: PyObjectWrap, +{ + #[inline(always)] + fn from(py_ref: T) -> Self { + py_ref.into_object() } } diff --git a/vm/src/types/mod.rs b/vm/src/types/mod.rs index 96f4e52ac..56d925bfa 100644 --- a/vm/src/types/mod.rs +++ b/vm/src/types/mod.rs @@ -1,5 +1,7 @@ mod slot; +mod structseq; mod zoo; pub use slot::*; +pub use structseq::PyStructSequence; pub(crate) use zoo::TypeZoo; diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs new file mode 100644 index 000000000..9ca0d6c12 --- /dev/null +++ b/vm/src/types/structseq.rs @@ -0,0 +1,89 @@ +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(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult> { + 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 = obj.try_into_value(vm)?; + if seq.len() != Self::FIELD_NAMES.len() { + return Err(vm.new_type_error(format!( + "{} takes a sequence of length {}", + typ.name(), + Self::FIELD_NAMES.len() + ))); + } + Ok(seq) + } + + #[pymethod(magic)] + fn repr(zelf: PyRef, vm: &VirtualMachine) -> PyResult { + 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> = 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, 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()) + }), + ); + } + } +} From f19143f3796af47c44d95da905c9b23fa0997f6f Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Mon, 18 Apr 2022 01:48:52 +0900 Subject: [PATCH 4/6] skip type check --- vm/src/types/structseq.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs index 9ca0d6c12..114310235 100644 --- a/vm/src/types/structseq.rs +++ b/vm/src/types/structseq.rs @@ -19,13 +19,13 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { fn try_elements_from(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult> { 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(), - ))); - } + // 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 = obj.try_into_value(vm)?; if seq.len() != Self::FIELD_NAMES.len() { return Err(vm.new_type_error(format!( From c35b3a653b12e93820177815e164f2cc61679b19 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 19 Apr 2022 05:16:33 +0900 Subject: [PATCH 5/6] hide PyStructSequence from crate root --- derive/src/pystructseq.rs | 4 ++-- stdlib/src/resource.rs | 3 ++- vm/src/stdlib/os.rs | 4 ++-- vm/src/stdlib/pwd.rs | 3 ++- vm/src/stdlib/sys.rs | 3 ++- vm/src/stdlib/time.rs | 3 ++- vm/src/version.rs | 2 +- 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/derive/src/pystructseq.rs b/derive/src/pystructseq.rs index 535b31fcd..dce8c4768 100644 --- a/derive/src/pystructseq.rs +++ b/derive/src/pystructseq.rs @@ -31,7 +31,7 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result 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( @@ -43,7 +43,7 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result } 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() } } }; diff --git a/stdlib/src/resource.rs b/stdlib/src/resource.rs index 046d86e5f..70d641974 100644 --- a/stdlib/src/resource.rs +++ b/stdlib/src/resource.rs @@ -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}; diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index acab029cc..e1d7289b7 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -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; diff --git a/vm/src/stdlib/pwd.rs b/vm/src/stdlib/pwd.rs index cea7ba6f1..bb9d5ca21 100644 --- a/vm/src/stdlib/pwd.rs +++ b/vm/src/stdlib/pwd.rs @@ -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; diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index 938fa77f3..c6cc06d6d 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -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}; diff --git a/vm/src/stdlib/time.rs b/vm/src/stdlib/time.rs index 91a958328..3641c5bc2 100644 --- a/vm/src/stdlib/time.rs +++ b/vm/src/stdlib/time.rs @@ -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}, diff --git a/vm/src/version.rs b/vm/src/version.rs index f29870277..cd26435df 100644 --- a/vm/src/version.rs +++ b/vm/src/version.rs @@ -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}; From 41000c4f545703c7dc7c53d0f0105b61d9f51cb4 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 19 Apr 2022 15:30:44 +0900 Subject: [PATCH 6/6] Use array for PyStructSequence --- vm/src/types/structseq.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs index 114310235..d56de4fb7 100644 --- a/vm/src/types/structseq.rs +++ b/vm/src/types/structseq.rs @@ -17,7 +17,10 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { .unwrap() } - fn try_elements_from(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult> { + fn try_elements_from( + 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!( @@ -27,13 +30,13 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { // ))); // } let seq: Vec = obj.try_into_value(vm)?; - if seq.len() != Self::FIELD_NAMES.len() { - return Err(vm.new_type_error(format!( + let seq: [PyObjectRef; FIELD_LEN] = seq.try_into().map_err(|_| { + vm.new_type_error(format!( "{} takes a sequence of length {}", typ.name(), - Self::FIELD_NAMES.len() - ))); - } + FIELD_LEN + )) + })?; Ok(seq) }