Merge pull request #1873 from youknowone/fromargs-generic

merge SplitArgs + Generic support for FromArgs
This commit is contained in:
Jeong YunWon
2020-04-25 03:37:55 +09:00
committed by GitHub
6 changed files with 135 additions and 138 deletions

View File

@@ -16,14 +16,11 @@ enum ParameterKind {
impl ParameterKind {
fn from_ident(ident: &Ident) -> Option<ParameterKind> {
if ident == "positional_only" {
Some(ParameterKind::PositionalOnly)
} else if ident == "positional_or_keyword" {
Some(ParameterKind::PositionalOrKeyword)
} else if ident == "keyword_only" {
Some(ParameterKind::KeywordOnly)
} else {
None
match ident.to_string().as_str() {
"positional_only" => Some(ParameterKind::PositionalOnly),
"positional_or_keyword" => Some(ParameterKind::PositionalOrKeyword),
"keyword_only" => Some(ParameterKind::KeywordOnly),
_ => None,
}
}
}
@@ -150,6 +147,13 @@ fn generate_field(field: &Field) -> Result<TokenStream2, Diagnostic> {
};
let name = &field.ident;
if let Some(name) = name {
if name.to_string().starts_with("_phantom") {
return Ok(quote! {
#name: std::marker::PhantomData,
});
}
}
let middle = quote! {
.map(|x| ::rustpython_vm::pyobject::TryFromObject::try_from_object(vm, x)).transpose()?
};
@@ -210,8 +214,9 @@ pub fn impl_from_args(input: DeriveInput) -> Result<TokenStream2, Diagnostic> {
};
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let output = quote! {
impl ::rustpython_vm::function::FromArgs for #name {
impl #impl_generics ::rustpython_vm::function::FromArgs for #name #ty_generics #where_clause {
fn from_args(
vm: &::rustpython_vm::VirtualMachine,
args: &mut ::rustpython_vm::function::PyFuncArgs

View File

@@ -4,16 +4,15 @@ use std::convert::TryFrom;
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use super::objbyteinner::{
ByteInnerExpandtabsOptions, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
ByteInnerSplitOptions, ByteInnerSplitlinesOptions, ByteInnerTranslateOptions, ByteOr,
PyByteInner,
ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions,
ByteInnerTranslateOptions, ByteOr, PyByteInner,
};
use super::objint::PyIntRef;
use super::objiter;
use super::objslice::PySliceRef;
use super::objstr::{PyString, PyStringRef};
use super::objtype::PyClassRef;
use super::pystr::PyCommonString;
use super::pystr::{self, PyCommonString};
use crate::cformat::CFormatString;
use crate::function::{OptionalArg, OptionalOption};
use crate::obj::objstr::do_cformat_string;
@@ -440,12 +439,12 @@ impl PyByteArray {
}
#[pymethod(name = "expandtabs")]
fn expandtabs(&self, options: ByteInnerExpandtabsOptions) -> PyByteArray {
fn expandtabs(&self, options: pystr::ExpandTabsArgs) -> PyByteArray {
self.borrow_value().expandtabs(options).into()
}
#[pymethod(name = "splitlines")]
fn splitlines(&self, options: ByteInnerSplitlinesOptions, vm: &VirtualMachine) -> PyResult {
fn splitlines(&self, options: pystr::SplitLinesArgs, vm: &VirtualMachine) -> PyResult {
let as_bytes = self
.borrow_value()
.splitlines(options)

View File

@@ -14,7 +14,7 @@ use super::objnone::PyNoneRef;
use super::objsequence::PySliceableSequence;
use super::objslice::PySliceRef;
use super::objstr::{self, PyString, PyStringRef};
use super::pystr::{self, PyCommonString, StringRange};
use super::pystr::{self, PyCommonString, PyCommonStringWrapper, StringRange};
use crate::function::{OptionalArg, OptionalOption};
use crate::pyhash;
use crate::pyobject::{
@@ -255,43 +255,7 @@ impl ByteInnerTranslateOptions {
}
}
#[derive(FromArgs)]
pub struct ByteInnerSplitOptions {
#[pyarg(positional_or_keyword, default = "None")]
sep: Option<PyByteInner>,
#[pyarg(positional_or_keyword, default = "-1")]
maxsplit: isize,
}
impl ByteInnerSplitOptions {
pub fn get_value(self, vm: &VirtualMachine) -> PyResult<(Option<Vec<u8>>, isize)> {
let sep = if let Some(s) = self.sep {
let sep = s.elements;
if sep.is_empty() {
return Err(vm.new_value_error("empty separator".to_owned()));
}
Some(sep)
} else {
None
};
Ok((sep, self.maxsplit))
}
}
#[derive(FromArgs)]
pub struct ByteInnerExpandtabsOptions {
#[pyarg(positional_or_keyword, optional = true)]
tabsize: OptionalArg<PyIntRef>,
}
impl ByteInnerExpandtabsOptions {
pub fn get_value(self) -> usize {
match self.tabsize.into_option() {
Some(int) => int.as_bigint().to_usize().unwrap_or(0),
None => 8,
}
}
}
pub type ByteInnerSplitOptions = pystr::SplitArgs<PyByteInner, [u8], u8>;
#[derive(FromArgs)]
pub struct ByteInnerSplitlinesOptions {
@@ -970,19 +934,13 @@ impl PyByteInner {
where
F: Fn(&[u8], &VirtualMachine) -> PyObjectRef,
{
let (sep, maxsplit) = options.get_value(vm)?;
let sep_ref = match sep {
Some(ref v) => Some(&v[..]),
None => None,
};
let elements = self.elements.py_split(
sep_ref,
maxsplit,
options,
vm,
|v, s, vm| v.split_str(s).map(|v| convert(v, vm)).collect(),
|v, s, n, vm| v.splitn_str(n, s).map(|v| convert(v, vm)).collect(),
|v, n, vm| v.py_split_whitespace(n, |v| convert(v, vm)),
);
)?;
Ok(vm.ctx.new_list(elements))
}
@@ -995,19 +953,13 @@ impl PyByteInner {
where
F: Fn(&[u8], &VirtualMachine) -> PyObjectRef,
{
let (sep, maxsplit) = options.get_value(vm)?;
let sep_ref = match sep {
Some(ref v) => Some(&v[..]),
None => None,
};
let mut elements = self.elements.py_split(
sep_ref,
maxsplit,
options,
vm,
|v, s, vm| v.rsplit_str(s).map(|v| convert(v, vm)).collect(),
|v, s, n, vm| v.rsplitn_str(n, s).map(|v| convert(v, vm)).collect(),
|v, n, vm| v.py_rsplit_whitespace(n, |v| convert(v, vm)),
);
)?;
elements.reverse();
Ok(vm.ctx.new_list(elements))
}
@@ -1050,8 +1002,8 @@ impl PyByteInner {
Ok((front, has_mid, back))
}
pub fn expandtabs(&self, options: ByteInnerExpandtabsOptions) -> Vec<u8> {
let tabsize = options.get_value();
pub fn expandtabs(&self, options: pystr::ExpandTabsArgs) -> Vec<u8> {
let tabsize = options.tabsize();
let mut counter: usize = 0;
let mut res = vec![];
@@ -1082,9 +1034,7 @@ impl PyByteInner {
res
}
pub fn splitlines(&self, options: ByteInnerSplitlinesOptions) -> Vec<&[u8]> {
let keepends = options.get_value();
pub fn splitlines(&self, options: pystr::SplitLinesArgs) -> Vec<&[u8]> {
let mut res = vec![];
if self.elements.is_empty() {
@@ -1093,7 +1043,7 @@ impl PyByteInner {
let mut prev_index = 0;
let mut index = 0;
let keep = if keepends { 1 } else { 0 };
let keep = if options.keepends { 1 } else { 0 };
let slice = &self.elements;
while index < slice.len() {
@@ -1435,13 +1385,23 @@ pub fn bytes_zfill(bytes: &[u8], width: usize) -> Vec<u8> {
}
}
impl PyCommonStringWrapper<[u8]> for PyByteInner {
fn as_ref(&self) -> &[u8] {
&self.elements
}
}
const ASCII_WHITESPACES: [u8; 6] = [0x20, 0x09, 0x0a, 0x0c, 0x0d, 0x0b];
impl PyCommonString<'_, u8> for [u8] {
impl PyCommonString<u8> for [u8] {
fn get_slice(&self, range: std::ops::Range<usize>) -> &Self {
&self[range]
}
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn len(&self) -> usize {
Self::len(self)
}

View File

@@ -4,15 +4,15 @@ use std::ops::Deref;
use std::str::FromStr;
use super::objbyteinner::{
ByteInnerExpandtabsOptions, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
ByteInnerSplitOptions, ByteInnerSplitlinesOptions, ByteInnerTranslateOptions, PyByteInner,
ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions,
ByteInnerTranslateOptions, PyByteInner,
};
use super::objint::PyIntRef;
use super::objiter;
use super::objslice::PySliceRef;
use super::objstr::{PyString, PyStringRef};
use super::objtype::PyClassRef;
use super::pystr::PyCommonString;
use super::pystr::{self, PyCommonString};
use crate::cformat::CFormatString;
use crate::function::{OptionalArg, OptionalOption};
use crate::obj::objstr::do_cformat_string;
@@ -401,12 +401,12 @@ impl PyBytes {
}
#[pymethod(name = "expandtabs")]
fn expandtabs(&self, options: ByteInnerExpandtabsOptions) -> PyBytes {
fn expandtabs(&self, options: pystr::ExpandTabsArgs) -> PyBytes {
self.inner.expandtabs(options).into()
}
#[pymethod(name = "splitlines")]
fn splitlines(&self, options: ByteInnerSplitlinesOptions, vm: &VirtualMachine) -> PyResult {
fn splitlines(&self, options: pystr::SplitLinesArgs, vm: &VirtualMachine) -> PyResult {
let as_bytes = self
.inner
.splitlines(options)

View File

@@ -21,7 +21,7 @@ use super::objsequence::PySliceableSequence;
use super::objslice::PySliceRef;
use super::objtuple;
use super::objtype::{self, PyClassRef};
use super::pystr::{adjust_indices, PyCommonString, StringRange};
use super::pystr::{self, adjust_indices, PyCommonString, PyCommonStringWrapper, StringRange};
use crate::cformat::{
CFormatPart, CFormatPreconversor, CFormatQuantity, CFormatSpec, CFormatString, CFormatType,
CNumberType,
@@ -168,18 +168,6 @@ struct StrArgs {
errors: OptionalArg<PyStringRef>,
}
#[derive(FromArgs)]
struct SplitLineArgs {
#[pyarg(positional_or_keyword, optional = true)]
keepends: OptionalArg<bool>,
}
#[derive(FromArgs)]
struct ExpandtabsArgs {
#[pyarg(positional_or_keyword, optional = true)]
tabsize: OptionalArg<usize>,
}
#[pyimpl(flags(BASETYPE))]
impl PyString {
#[pyslot]
@@ -457,26 +445,24 @@ impl PyString {
#[pymethod]
fn split(&self, args: SplitArgs, vm: &VirtualMachine) -> PyResult {
let elements = self.value.py_split(
args.non_empty_sep(vm)?,
args.maxsplit,
args,
vm,
|v, s, vm| v.split(s).map(|s| vm.ctx.new_str(s)).collect(),
|v, s, n, vm| v.splitn(n, s).map(|s| vm.ctx.new_str(s)).collect(),
|v, n, vm| v.py_split_whitespace(n, |s| vm.ctx.new_str(s)),
);
)?;
Ok(vm.ctx.new_list(elements))
}
#[pymethod]
fn rsplit(&self, args: SplitArgs, vm: &VirtualMachine) -> PyResult {
let mut elements = self.value.py_split(
args.non_empty_sep(vm)?,
args.maxsplit,
args,
vm,
|v, s, vm| v.rsplit(s).map(|s| vm.ctx.new_str(s)).collect(),
|v, s, n, vm| v.rsplitn(n, s).map(|s| vm.ctx.new_str(s)).collect(),
|v, n, vm| v.py_rsplit_whitespace(n, |s| vm.ctx.new_str(s)),
);
)?;
// Unlike Python rsplit, Rust rsplitn returns an iterator that
// starts from the end of the string.
elements.reverse();
@@ -799,14 +785,13 @@ impl PyString {
}
#[pymethod]
fn splitlines(&self, args: SplitLineArgs, vm: &VirtualMachine) -> PyObjectRef {
let keepends = args.keepends.unwrap_or(false);
fn splitlines(&self, args: pystr::SplitLinesArgs, vm: &VirtualMachine) -> PyObjectRef {
let mut elements = vec![];
let mut curr = "".to_owned();
let mut chars = self.value.chars().peekable();
while let Some(ch) = chars.next() {
if ch == '\n' || ch == '\r' {
if keepends {
if args.keepends {
curr.push(ch);
}
if ch == '\r' && chars.peek() == Some(&'\n') {
@@ -1082,8 +1067,8 @@ impl PyString {
}
#[pymethod]
fn expandtabs(&self, args: ExpandtabsArgs) -> String {
let tab_stop = args.tabsize.unwrap_or(8);
fn expandtabs(&self, args: pystr::ExpandTabsArgs) -> String {
let tab_stop = args.tabsize();
let mut expanded_str = String::with_capacity(self.value.len());
let mut tab_size = tab_stop;
let mut col_count = 0 as usize;
@@ -1298,28 +1283,7 @@ impl TryFromObject for std::ffi::CString {
}
}
#[derive(FromArgs)]
struct SplitArgs {
#[pyarg(positional_or_keyword, default = "None")]
sep: Option<PyStringRef>,
#[pyarg(positional_or_keyword, default = "-1")]
maxsplit: isize,
}
impl SplitArgs {
fn non_empty_sep<'a>(&'a self, vm: &VirtualMachine) -> PyResult<Option<&'a str>> {
let sep = if let Some(s) = self.sep.as_ref() {
let sep = s.as_str();
if sep.is_empty() {
return Err(vm.new_value_error("empty separator".to_owned()));
}
Some(sep)
} else {
None
};
Ok(sep)
}
}
type SplitArgs = pystr::SplitArgs<PyStringRef, str, char>;
pub fn init(ctx: &PyContext) {
PyString::extend_class(ctx, &ctx.types.str_type);
@@ -1799,11 +1763,21 @@ mod tests {
}
}
impl PyCommonString<'_, char> for str {
impl PyCommonStringWrapper<str> for PyStringRef {
fn as_ref(&self) -> &str {
self.value.as_str()
}
}
impl PyCommonString<char> for str {
fn get_slice(&self, range: std::ops::Range<usize>) -> &Self {
&self[range]
}
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn len(&self) -> usize {
Self::len(self)
}

View File

@@ -1,6 +1,58 @@
use crate::function::{single_or_tuple_any, OptionalOption};
use crate::pyobject::{PyObjectRef, PyResult, TryFromObject, TypeProtocol};
use crate::vm::VirtualMachine;
use num_traits::cast::ToPrimitive;
#[derive(FromArgs)]
pub struct SplitArgs<T, S, E>
where
T: TryFromObject + PyCommonStringWrapper<S>,
S: ?Sized + PyCommonString<E>,
{
#[pyarg(positional_or_keyword, default = "None")]
sep: Option<T>,
#[pyarg(positional_or_keyword, default = "-1")]
maxsplit: isize,
_phantom1: std::marker::PhantomData<S>,
_phantom2: std::marker::PhantomData<E>,
}
impl<T, S, E> SplitArgs<T, S, E>
where
T: TryFromObject + PyCommonStringWrapper<S>,
S: ?Sized + PyCommonString<E>,
{
pub fn get_value(self, vm: &VirtualMachine) -> PyResult<(Option<T>, isize)> {
let sep = if let Some(s) = self.sep {
let sep = s.as_ref();
if sep.is_empty() {
return Err(vm.new_value_error("empty separator".to_owned()));
}
Some(s)
} else {
None
};
Ok((sep, self.maxsplit))
}
}
#[derive(FromArgs)]
pub struct SplitLinesArgs {
#[pyarg(positional_or_keyword, default = "false")]
pub keepends: bool,
}
#[derive(FromArgs)]
pub struct ExpandTabsArgs {
#[pyarg(positional_or_keyword, default = "8")]
tabsize: isize,
}
impl ExpandTabsArgs {
pub fn tabsize(&self) -> usize {
self.tabsize.to_usize().unwrap_or(0)
}
}
// help get optional string indices
pub fn adjust_indices(
@@ -37,36 +89,43 @@ impl StringRange for std::ops::Range<usize> {
}
}
pub trait PyCommonString<'a, E>
pub trait PyCommonStringWrapper<S>
where
Self: 'a,
S: ?Sized,
{
fn as_ref(&self) -> &S;
}
pub trait PyCommonString<E> {
fn get_slice(&self, range: std::ops::Range<usize>) -> &Self;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn py_split<SP, SN, SW, R>(
fn py_split<T, SP, SN, SW, R>(
&self,
sep: Option<&Self>,
maxsplit: isize,
args: SplitArgs<T, Self, E>,
vm: &VirtualMachine,
split: SP,
splitn: SN,
splitw: SW,
) -> Vec<R>
) -> PyResult<Vec<R>>
where
T: TryFromObject + PyCommonStringWrapper<Self>,
SP: Fn(&Self, &Self, &VirtualMachine) -> Vec<R>,
SN: Fn(&Self, &Self, usize, &VirtualMachine) -> Vec<R>,
SW: Fn(&Self, isize, &VirtualMachine) -> Vec<R>,
{
if let Some(pattern) = sep {
let (sep, maxsplit) = args.get_value(vm)?;
let splited = if let Some(pattern) = sep {
if maxsplit < 0 {
split(self, pattern, vm)
split(self, pattern.as_ref(), vm)
} else {
splitn(self, pattern, (maxsplit + 1) as usize, vm)
splitn(self, pattern.as_ref(), (maxsplit + 1) as usize, vm)
}
} else {
splitw(self, maxsplit, vm)
}
};
Ok(splited)
}
fn py_split_whitespace<F>(&self, maxsplit: isize, convert: F) -> Vec<PyObjectRef>
where