Skip to content

Commit 73dbcfb

Browse files
committed
Add bytes.center
fix str.center add some tests introduce is_byte
1 parent bd78f7e commit 73dbcfb

File tree

5 files changed

+147
-3
lines changed

5 files changed

+147
-3
lines changed

tests/snippets/bytes.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,30 @@
131131
except ValueError as e:
132132
str(e) == "non-hexadecimal number found in fromhex() arg at position 1"
133133

134+
# center
135+
assert [b"koki".center(i, b"|") for i in range(3, 10)] == [
136+
b"koki",
137+
b"koki",
138+
b"|koki",
139+
b"|koki|",
140+
b"||koki|",
141+
b"||koki||",
142+
b"|||koki||",
143+
]
144+
145+
assert [b"kok".center(i, b"|") for i in range(2, 10)] == [
146+
b"kok",
147+
b"kok",
148+
b"kok|",
149+
b"|kok|",
150+
b"|kok||",
151+
b"||kok||",
152+
b"||kok|||",
153+
b"|||kok|||",
154+
]
155+
b"kok".center(4) == b" kok" # " test no arg"
156+
with assertRaises(TypeError):
157+
b"b".center(2, "a")
158+
with assertRaises(TypeError):
159+
b"b".center(2, b"ba")
160+
b"kok".center(5, bytearray(b"x"))

tests/snippets/strings.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,29 @@
5555
c = 'hallo'
5656
assert c.capitalize() == 'Hallo'
5757
assert c.center(11, '-') == '---hallo---'
58+
assert ["koki".center(i, "|") for i in range(3, 10)] == [
59+
"koki",
60+
"koki",
61+
"|koki",
62+
"|koki|",
63+
"||koki|",
64+
"||koki||",
65+
"|||koki||",
66+
]
67+
68+
69+
assert ["kok".center(i, "|") for i in range(2, 10)] == [
70+
"kok",
71+
"kok",
72+
"kok|",
73+
"|kok|",
74+
"|kok||",
75+
"||kok||",
76+
"||kok|||",
77+
"|||kok|||",
78+
]
79+
80+
5881
# assert c.isascii()
5982
assert c.index('a') == 1
6083
assert c.rindex('l') == 3

vm/src/obj/objbyteinner.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::pyobject::PyObjectRef;
2+
use num_bigint::BigInt;
23

34
use crate::function::OptionalArg;
45

@@ -13,8 +14,12 @@ use std::hash::{Hash, Hasher};
1314
use super::objint;
1415
use super::objsequence::PySliceableSequence;
1516
use crate::obj::objint::PyInt;
17+
use num_integer::Integer;
1618
use num_traits::ToPrimitive;
1719

20+
use super::objbytearray::{get_value as get_value_bytearray, PyByteArray};
21+
use super::objbytes::PyBytes;
22+
1823
#[derive(Debug, Default, Clone)]
1924
pub struct PyByteInner {
2025
pub elements: Vec<u8>,
@@ -355,4 +360,39 @@ impl PyByteInner {
355360
.map(|x| x.unwrap())
356361
.collect::<Vec<u8>>())
357362
}
363+
364+
pub fn center(&self, width: &BigInt, fillbyte: u8, _vm: &VirtualMachine) -> Vec<u8> {
365+
let width = width.to_usize().unwrap();
366+
367+
// adjust right et left side
368+
if width <= self.len() {
369+
return self.elements.clone();
370+
}
371+
let diff: usize = width - self.len();
372+
let mut ln: usize = diff / 2;
373+
let mut rn: usize = ln;
374+
375+
if diff.is_odd() && self.len() % 2 == 0 {
376+
ln += 1
377+
}
378+
379+
if diff.is_odd() && self.len() % 2 != 0 {
380+
rn += 1
381+
}
382+
383+
// merge all
384+
let mut res = vec![fillbyte; ln];
385+
res.extend_from_slice(&self.elements[..]);
386+
res.extend_from_slice(&vec![fillbyte; rn][..]);
387+
388+
res
389+
}
390+
}
391+
392+
pub fn is_byte(obj: &PyObjectRef) -> Option<Vec<u8>> {
393+
match_class!(obj.clone(),
394+
395+
i @ PyBytes => Some(i.get_value().to_vec()),
396+
j @ PyByteArray => Some(get_value_bytearray(&j.as_object()).to_vec()),
397+
_ => None)
358398
}

vm/src/obj/objbytes.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::ops::Deref;
77
use crate::function::OptionalArg;
88
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
99

10-
use super::objbyteinner::PyByteInner;
10+
use super::objbyteinner::{is_byte, PyByteInner};
1111
use super::objiter;
1212
use super::objslice::PySlice;
1313
use super::objtype::PyClassRef;
@@ -34,6 +34,10 @@ impl PyBytes {
3434
inner: PyByteInner { elements },
3535
}
3636
}
37+
38+
pub fn get_value(&self) -> &[u8] {
39+
&self.inner.elements
40+
}
3741
}
3842

3943
impl Deref for PyBytes {
@@ -229,6 +233,42 @@ impl PyBytesRef {
229233
obj => Err(vm.new_type_error(format!("fromhex() argument must be str, not {}", obj )))
230234
)
231235
}
236+
237+
#[pymethod(name = "center")]
238+
fn center(
239+
self,
240+
width: PyObjectRef,
241+
fillbyte: OptionalArg<PyObjectRef>,
242+
vm: &VirtualMachine,
243+
) -> PyResult {
244+
let sym = if let OptionalArg::Present(v) = fillbyte {
245+
match is_byte(&v) {
246+
Some(x) => {
247+
if x.len() == 1 {
248+
x[0]
249+
} else {
250+
return Err(vm.new_type_error(format!(
251+
"center() argument 2 must be a byte string of length 1, not {}",
252+
&v
253+
)));
254+
}
255+
}
256+
None => {
257+
return Err(vm.new_type_error(format!(
258+
"center() argument 2 must be a byte string of length 1, not {}",
259+
&v
260+
)));
261+
}
262+
}
263+
} else {
264+
32 // default is space
265+
};
266+
267+
match_class!(width,
268+
i @PyInt => Ok(vm.ctx.new_bytes(self.inner.center(i.as_bigint(), sym, vm))),
269+
obj => {Err(vm.new_type_error(format!("{} cannot be interpreted as an integer", obj)))}
270+
)
271+
}
232272
}
233273

234274
#[derive(Debug)]

vm/src/obj/objstr.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,8 +691,22 @@ impl PyStringRef {
691691
) -> PyResult<String> {
692692
let value = &self.value;
693693
let rep_char = Self::get_fill_char(&rep, vm)?;
694-
let left_buff: usize = (len - value.len()) / 2;
695-
let right_buff = len - value.len() - left_buff;
694+
let value_len = self.value.chars().count();
695+
696+
if len <= value_len {
697+
return Ok(value.to_string());
698+
}
699+
let diff: usize = len - value_len;
700+
let mut left_buff: usize = diff / 2;
701+
let mut right_buff: usize = left_buff;
702+
703+
if diff % 2 != 0 && value_len % 2 == 0 {
704+
left_buff += 1
705+
}
706+
707+
if diff % 2 != 0 && value_len % 2 != 0 {
708+
right_buff += 1
709+
}
696710
Ok(format!(
697711
"{}{}{}",
698712
rep_char.repeat(left_buff),

0 commit comments

Comments
 (0)