mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-17 01:51:39 +09:00
192 lines
6.5 KiB
Rust
192 lines
6.5 KiB
Rust
use crate::pyobject::PyObjectRef;
|
|
|
|
use crate::function::OptionalArg;
|
|
|
|
use crate::vm::VirtualMachine;
|
|
|
|
use crate::pyobject::{PyResult, TypeProtocol};
|
|
|
|
use crate::obj::objstr::PyString;
|
|
use std::collections::hash_map::DefaultHasher;
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
use super::objint;
|
|
use crate::obj::objint::PyInt;
|
|
use num_traits::ToPrimitive;
|
|
|
|
#[derive(Debug, Default, Clone)]
|
|
pub struct PyByteInner {
|
|
pub elements: Vec<u8>,
|
|
}
|
|
|
|
impl PyByteInner {
|
|
pub fn new(
|
|
val_option: OptionalArg<PyObjectRef>,
|
|
enc_option: OptionalArg<PyObjectRef>,
|
|
vm: &VirtualMachine,
|
|
) -> PyResult<PyByteInner> {
|
|
// First handle bytes(string, encoding[, errors])
|
|
if let OptionalArg::Present(enc) = enc_option {
|
|
if let OptionalArg::Present(eval) = val_option {
|
|
if let Ok(input) = eval.downcast::<PyString>() {
|
|
if let Ok(encoding) = enc.clone().downcast::<PyString>() {
|
|
if encoding.value.to_lowercase() == "utf8".to_string()
|
|
|| encoding.value.to_lowercase() == "utf-8".to_string()
|
|
// TODO: different encoding
|
|
{
|
|
return Ok(PyByteInner {
|
|
elements: input.value.as_bytes().to_vec(),
|
|
});
|
|
} else {
|
|
return Err(
|
|
vm.new_value_error(format!("unknown encoding: {}", encoding.value)), //should be lookup error
|
|
);
|
|
}
|
|
} else {
|
|
return Err(vm.new_type_error(format!(
|
|
"bytes() argument 2 must be str, not {}",
|
|
enc.class().name
|
|
)));
|
|
}
|
|
} else {
|
|
return Err(vm.new_type_error("encoding without a string argument".to_string()));
|
|
}
|
|
} else {
|
|
return Err(vm.new_type_error("encoding without a string argument".to_string()));
|
|
}
|
|
// On ly one argument
|
|
} else {
|
|
let value = if let OptionalArg::Present(ival) = val_option {
|
|
match_class!(ival.clone(),
|
|
i @ PyInt => {
|
|
let size = objint::get_value(&i.into_object()).to_usize().unwrap();
|
|
let mut res: Vec<u8> = Vec::with_capacity(size);
|
|
for _ in 0..size {
|
|
res.push(0)
|
|
}
|
|
Ok(res)},
|
|
_l @ PyString=> {return Err(vm.new_type_error(format!(
|
|
"string argument without an encoding"
|
|
)));},
|
|
obj => {
|
|
let elements = vm.extract_elements(&obj).or_else(|_| {return Err(vm.new_type_error(format!(
|
|
"cannot convert {} object to bytes", obj.class().name)));});
|
|
|
|
let mut data_bytes = vec![];
|
|
for elem in elements.unwrap(){
|
|
let v = objint::to_int(vm, &elem, 10)?;
|
|
if let Some(i) = v.to_u8() {
|
|
data_bytes.push(i);
|
|
} else {
|
|
return Err(vm.new_value_error("bytes must be in range(0, 256)".to_string()));
|
|
}
|
|
|
|
}
|
|
Ok(data_bytes)
|
|
}
|
|
)
|
|
} else {
|
|
Ok(vec![])
|
|
};
|
|
match value {
|
|
Ok(val) => Ok(PyByteInner { elements: val }),
|
|
Err(err) => Err(err),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn repr(&self) -> PyResult<String> {
|
|
let mut res = String::with_capacity(self.elements.len());
|
|
for i in self.elements.iter() {
|
|
match i {
|
|
0..=8 => res.push_str(&format!("\\x0{}", i)),
|
|
9 => res.push_str("\\t"),
|
|
10 => res.push_str("\\n"),
|
|
13 => res.push_str("\\r"),
|
|
32..=126 => res.push(*(i) as char),
|
|
_ => res.push_str(&format!("\\x{:x}", i)),
|
|
}
|
|
}
|
|
Ok(res)
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.elements.len()
|
|
}
|
|
|
|
pub fn eq(&self, other: &PyByteInner, vm: &VirtualMachine) -> PyResult {
|
|
if self.elements == other.elements {
|
|
Ok(vm.new_bool(true))
|
|
} else {
|
|
Ok(vm.new_bool(false))
|
|
}
|
|
}
|
|
|
|
pub fn ge(&self, other: &PyByteInner, vm: &VirtualMachine) -> PyResult {
|
|
if self.elements >= other.elements {
|
|
Ok(vm.new_bool(true))
|
|
} else {
|
|
Ok(vm.new_bool(false))
|
|
}
|
|
}
|
|
|
|
pub fn le(&self, other: &PyByteInner, vm: &VirtualMachine) -> PyResult {
|
|
if self.elements <= other.elements {
|
|
Ok(vm.new_bool(true))
|
|
} else {
|
|
Ok(vm.new_bool(false))
|
|
}
|
|
}
|
|
|
|
pub fn gt(&self, other: &PyByteInner, vm: &VirtualMachine) -> PyResult {
|
|
if self.elements > other.elements {
|
|
Ok(vm.new_bool(true))
|
|
} else {
|
|
Ok(vm.new_bool(false))
|
|
}
|
|
}
|
|
|
|
pub fn lt(&self, other: &PyByteInner, vm: &VirtualMachine) -> PyResult {
|
|
if self.elements < other.elements {
|
|
Ok(vm.new_bool(true))
|
|
} else {
|
|
Ok(vm.new_bool(false))
|
|
}
|
|
}
|
|
|
|
pub fn hash(&self) -> usize {
|
|
let mut hasher = DefaultHasher::new();
|
|
self.elements.hash(&mut hasher);
|
|
hasher.finish() as usize
|
|
}
|
|
|
|
pub fn add(&self, other: &PyByteInner, vm: &VirtualMachine) -> PyResult {
|
|
let elements: Vec<u8> = self
|
|
.elements
|
|
.iter()
|
|
.chain(other.elements.iter())
|
|
.cloned()
|
|
.collect();
|
|
Ok(vm.ctx.new_bytes(elements))
|
|
}
|
|
|
|
pub fn contains_bytes(&self, other: &PyByteInner, vm: &VirtualMachine) -> PyResult {
|
|
for (n, i) in self.elements.iter().enumerate() {
|
|
if n + other.len() <= self.len() && *i == other.elements[0] {
|
|
if &self.elements[n..n + other.len()] == other.elements.as_slice() {
|
|
return Ok(vm.new_bool(true));
|
|
}
|
|
}
|
|
}
|
|
Ok(vm.new_bool(false))
|
|
}
|
|
|
|
pub fn contains_int(&self, int: &PyInt, vm: &VirtualMachine) -> PyResult {
|
|
self.elements.contains(int);
|
|
Ok(vm.new_bool(false))
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
// fix b"é" not allowed should be bytes("é", "utf8")
|