mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Enable some pedantic clippy lints (#7764)
This commit is contained in:
1 parent
bc29e21a9d
commit
323a45ef07
100 files changed
+471
-106
No files matched your search
+17
-5
@@ -297,6 +297,20 @@ elided_lifetimes_in_paths = "warn"
|
||||
unreachable_pub = "warn"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
correctness = { level = "warn", priority = -2 }
|
||||
suspicious = { level = "warn", priority = -2 }
|
||||
perf = { level = "warn", priority = -2 }
|
||||
style = { level = "warn", priority = -2 }
|
||||
complexity = { level = "warn", priority = -2 }
|
||||
# pedantic = { level = "warn", priority = -2 } # TODO: Enable this
|
||||
|
||||
missing_errors_doc = "allow" # Too many errors. No auto-fix available
|
||||
missing_panics_doc = "allow" # Too many errors. No auto-fix available
|
||||
match_same_arms = "allow" # Not always more readable
|
||||
if_not_else = "allow" # Not always more readable
|
||||
single_match_else = "allow"
|
||||
similar_names = "allow"
|
||||
|
||||
alloc_instead_of_core = "warn"
|
||||
std_instead_of_alloc = "warn"
|
||||
std_instead_of_core = "warn"
|
||||
@@ -310,8 +324,6 @@ manual_is_variant_and = "warn"
|
||||
or_fun_call = "warn"
|
||||
unnested_or_patterns = "warn"
|
||||
|
||||
perf = "warn"
|
||||
style = "warn"
|
||||
complexity = "warn"
|
||||
suspicious = "warn"
|
||||
correctness = "warn"
|
||||
# pedantic lints to enforce gradually
|
||||
cloned_instead_of_copied = "warn"
|
||||
must_use_candidate = "warn"
|
||||
@@ -417,6 +417,7 @@ impl Default for PatternContext {
|
||||
}
|
||||
|
||||
impl PatternContext {
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
stores: Vec::new(),
|
||||
@@ -426,6 +427,7 @@ impl PatternContext {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn fail_pop_size(&self) -> usize {
|
||||
self.fail_pop.len()
|
||||
}
|
||||
@@ -6266,12 +6268,11 @@ impl Compiler {
|
||||
return Err(self.error(CodegenErrorType::UnreachablePattern(
|
||||
PatternUnreachableReason::NameCapture,
|
||||
)));
|
||||
} else {
|
||||
// A wildcard makes remaining patterns unreachable.
|
||||
return Err(self.error(CodegenErrorType::UnreachablePattern(
|
||||
PatternUnreachableReason::Wildcard,
|
||||
)));
|
||||
}
|
||||
// A wildcard makes remaining patterns unreachable.
|
||||
return Err(self.error(CodegenErrorType::UnreachablePattern(
|
||||
PatternUnreachableReason::Wildcard,
|
||||
)));
|
||||
}
|
||||
// If irrefutable matches are allowed, store the name (if any).
|
||||
return self.pattern_helper_store_name(p.name.as_ref(), pc);
|
||||
@@ -10327,9 +10328,8 @@ impl Compiler {
|
||||
if !found_loop {
|
||||
if is_break {
|
||||
return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range));
|
||||
} else {
|
||||
return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
|
||||
}
|
||||
return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
@@ -10368,9 +10368,8 @@ impl Compiler {
|
||||
let Some(loop_idx) = loop_idx else {
|
||||
if is_break {
|
||||
return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range));
|
||||
} else {
|
||||
return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
|
||||
}
|
||||
return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
|
||||
};
|
||||
|
||||
let loop_block = code.fblock[loop_idx].fb_block;
|
||||
|
||||
@@ -125,6 +125,7 @@ impl SymbolTable {
|
||||
builder.finish()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn lookup(&self, name: &str) -> Option<&Symbol> {
|
||||
self.symbols.get(name)
|
||||
}
|
||||
@@ -226,6 +227,7 @@ impl Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_global(&self) -> bool {
|
||||
matches!(
|
||||
self.scope,
|
||||
@@ -233,10 +235,12 @@ impl Symbol {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_local(&self) -> bool {
|
||||
matches!(self.scope, SymbolScope::Local | SymbolScope::Cell)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_bound(&self) -> bool {
|
||||
self.flags.intersects(SymbolFlags::BOUND)
|
||||
}
|
||||
@@ -249,6 +253,7 @@ pub struct SymbolTableError {
|
||||
}
|
||||
|
||||
impl SymbolTableError {
|
||||
#[must_use]
|
||||
pub fn into_codegen_error(self, source_path: String) -> CodegenError {
|
||||
CodegenError {
|
||||
location: self.location,
|
||||
|
||||
@@ -64,6 +64,7 @@ impl<T> Default for OncePtr<T> {
|
||||
|
||||
impl<T> OncePtr<T> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Radium::new(ptr::null_mut()),
|
||||
|
||||
@@ -38,6 +38,7 @@ macro_rules! panic_oob {
|
||||
}
|
||||
|
||||
impl<T> BoxVec<T> {
|
||||
#[must_use]
|
||||
pub fn new(n: usize) -> Self {
|
||||
Self {
|
||||
xs: Box::new_uninit_slice(n),
|
||||
@@ -46,24 +47,29 @@ impl<T> BoxVec<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn capacity(&self) -> usize {
|
||||
self.xs.len()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_full(&self) -> bool {
|
||||
self.len() == self.capacity()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn remaining_capacity(&self) -> usize {
|
||||
self.capacity() - self.len()
|
||||
}
|
||||
@@ -312,6 +318,7 @@ impl<T> BoxVec<T> {
|
||||
}
|
||||
|
||||
/// Return a slice containing all elements of the vector.
|
||||
#[must_use]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
self
|
||||
}
|
||||
@@ -323,6 +330,7 @@ impl<T> BoxVec<T> {
|
||||
|
||||
/// Return a raw pointer to the vector's buffer.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
self.xs.as_ptr().cast()
|
||||
}
|
||||
@@ -487,6 +495,7 @@ impl<T> DoubleEndedIterator for Drain<'_, T> {
|
||||
impl<T> ExactSizeIterator for Drain<'_, T> {}
|
||||
|
||||
impl<'a, T> Drain<'a, T> {
|
||||
#[must_use]
|
||||
pub fn as_slice(&self) -> &'a [T] {
|
||||
self.iter.as_slice()
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ pub enum CFormatType {
|
||||
}
|
||||
|
||||
impl CFormatType {
|
||||
#[must_use]
|
||||
pub const fn to_char(self) -> char {
|
||||
match self {
|
||||
Self::Number(x) => x as u8 as char,
|
||||
@@ -137,6 +138,7 @@ bitflags! {
|
||||
|
||||
impl CConversionFlags {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn sign_string(&self) -> &'static str {
|
||||
if self.contains(Self::SIGN_CHAR) {
|
||||
"+"
|
||||
@@ -408,6 +410,7 @@ impl CFormatSpec {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn format_bytes(&self, bytes: &[u8]) -> Vec<u8> {
|
||||
let bytes = if let Some(CFormatPrecision::Quantity(CFormatQuantity::Amount(precision))) =
|
||||
self.precision
|
||||
@@ -432,6 +435,7 @@ impl CFormatSpec {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn format_number(&self, num: &BigInt) -> String {
|
||||
use CNumberType::*;
|
||||
let CFormatType::Number(format_type) = self.format_type else {
|
||||
@@ -492,6 +496,7 @@ impl CFormatSpec {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn format_float(&self, num: f64) -> String {
|
||||
let sign_string = if num.is_sign_negative() && !num.is_nan() {
|
||||
"-"
|
||||
@@ -740,6 +745,7 @@ pub struct CFormatStrOrBytes<S> {
|
||||
}
|
||||
|
||||
impl<S> CFormatStrOrBytes<S> {
|
||||
#[must_use]
|
||||
pub fn check_specifiers(&self) -> Option<(usize, bool)> {
|
||||
let mut count = 0;
|
||||
let mut mapping_required = false;
|
||||
@@ -828,7 +834,7 @@ pub type CFormatBytes = CFormatStrOrBytes<Vec<u8>>;
|
||||
|
||||
impl CFormatBytes {
|
||||
pub fn parse_from_bytes(bytes: &[u8]) -> Result<Self, CFormatError> {
|
||||
let mut iter = bytes.iter().cloned().enumerate().peekable();
|
||||
let mut iter = bytes.iter().copied().enumerate().peekable();
|
||||
Self::parse(&mut iter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use core::f64;
|
||||
use malachite_bigint::{BigInt, ToBigInt};
|
||||
use num_traits::{Signed, ToPrimitive};
|
||||
|
||||
#[must_use]
|
||||
pub const fn decompose_float(value: f64) -> (f64, i32) {
|
||||
if 0.0 == value {
|
||||
(0.0, 0i32)
|
||||
@@ -29,6 +30,7 @@ pub const fn decompose_float(value: f64) -> (f64, i32) {
|
||||
/// assert!(!eq_int(c, &b));
|
||||
/// ```
|
||||
///
|
||||
#[must_use]
|
||||
pub fn eq_int(value: f64, other: &BigInt) -> bool {
|
||||
if let (Some(self_int), Some(other_float)) = (value.to_bigint(), other.to_f64()) {
|
||||
value == other_float && self_int == *other
|
||||
@@ -37,6 +39,7 @@ pub fn eq_int(value: f64, other: &BigInt) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn lt_int(value: f64, other_int: &BigInt) -> bool {
|
||||
match (value.to_bigint(), other_int.to_f64()) {
|
||||
(Some(self_int), Some(other_float)) => value < other_float || self_int < *other_int,
|
||||
@@ -50,6 +53,7 @@ pub fn lt_int(value: f64, other_int: &BigInt) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gt_int(value: f64, other_int: &BigInt) -> bool {
|
||||
match (value.to_bigint(), other_int.to_f64()) {
|
||||
(Some(self_int), Some(other_float)) => value > other_float || self_int > *other_int,
|
||||
@@ -63,14 +67,17 @@ pub fn gt_int(value: f64, other_int: &BigInt) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn div(v1: f64, v2: f64) -> Option<f64> {
|
||||
if v2 != 0.0 { Some(v1 / v2) } else { None }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mod_(v1: f64, v2: f64) -> Option<f64> {
|
||||
divmod(v1, v2).map(|(_, m)| m)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn floordiv(v1: f64, v2: f64) -> Option<f64> {
|
||||
divmod(v1, v2).map(|(d, _)| d)
|
||||
}
|
||||
@@ -78,6 +85,7 @@ pub fn floordiv(v1: f64, v2: f64) -> Option<f64> {
|
||||
// Canonical (floordiv, mod) for floats matching CPython's _float_div_mod
|
||||
// (Objects/floatobject.c). `mod_` and `floordiv` delegate here so that
|
||||
// `divmod(a, b) == (a // b, a % b)` holds by construction.
|
||||
#[must_use]
|
||||
pub fn divmod(v1: f64, v2: f64) -> Option<(f64, f64)> {
|
||||
if v2 == 0.0 {
|
||||
return None;
|
||||
@@ -108,6 +116,7 @@ pub fn divmod(v1: f64, v2: f64) -> Option<(f64, f64)> {
|
||||
|
||||
// nextafter algorithm based off of https://gitlab.com/bronsonbdevost/next_afterf
|
||||
#[allow(clippy::float_cmp)]
|
||||
#[must_use]
|
||||
pub fn nextafter(x: f64, y: f64) -> f64 {
|
||||
if x == y {
|
||||
y
|
||||
@@ -130,6 +139,7 @@ pub fn nextafter(x: f64, y: f64) -> f64 {
|
||||
}
|
||||
|
||||
#[allow(clippy::float_cmp)]
|
||||
#[must_use]
|
||||
pub fn nextafter_with_steps(x: f64, y: f64, steps: u64) -> f64 {
|
||||
if x == y {
|
||||
y
|
||||
@@ -192,6 +202,7 @@ pub fn nextafter_with_steps(x: f64, y: f64, steps: u64) -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn ulp(x: f64) -> f64 {
|
||||
if x.is_nan() {
|
||||
return x;
|
||||
@@ -207,6 +218,7 @@ pub fn ulp(x: f64) -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn round_float_digits(x: f64, ndigits: i32) -> Option<f64> {
|
||||
// Mirror CPython's `float.__round__` (Objects/floatobject.c), which uses
|
||||
// `_Py_dg_dtoa` to round at the decimal level. Multiplying by 10**ndigits
|
||||
|
||||
@@ -53,6 +53,7 @@ impl FormatParse for FormatConversion {
|
||||
}
|
||||
|
||||
impl FormatConversion {
|
||||
#[must_use]
|
||||
pub fn from_char(c: CodePoint) -> Option<Self> {
|
||||
match c.to_char_lossy() {
|
||||
's' => Some(Self::Str),
|
||||
@@ -479,6 +480,7 @@ impl FormatSpec {
|
||||
}
|
||||
|
||||
/// Returns true if this format spec uses the locale-aware 'n' format type.
|
||||
#[must_use]
|
||||
pub fn has_locale_format(&self) -> bool {
|
||||
matches!(self.format_type, Some(FormatType::Number(Case::Lower)))
|
||||
}
|
||||
@@ -487,6 +489,7 @@ impl FormatSpec {
|
||||
/// subject to `sys.get_int_max_str_digits()` (no spec, 'd', or 'n').
|
||||
/// Binary bases ('b', 'o', 'x', 'X') are exempt per CPython. 'N' is rejected
|
||||
/// later in `format_int` as `UnknownFormatCode`, so it is not included here.
|
||||
#[must_use]
|
||||
pub fn is_decimal_int_format(&self) -> bool {
|
||||
matches!(
|
||||
self.format_type,
|
||||
@@ -1354,20 +1357,18 @@ impl FormatString {
|
||||
} else if c == '{' {
|
||||
if nested {
|
||||
return Err(FormatParseError::InvalidFormatSpecifier);
|
||||
} else {
|
||||
nested = true;
|
||||
left.push(c);
|
||||
continue;
|
||||
}
|
||||
nested = true;
|
||||
left.push(c);
|
||||
continue;
|
||||
} else if c == '}' {
|
||||
if nested {
|
||||
nested = false;
|
||||
left.push(c);
|
||||
continue;
|
||||
} else {
|
||||
end_bracket_pos = Some(idx);
|
||||
break;
|
||||
}
|
||||
end_bracket_pos = Some(idx);
|
||||
break;
|
||||
} else {
|
||||
left.push(c);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ impl BuildHasher for HashSecret {
|
||||
}
|
||||
|
||||
impl HashSecret {
|
||||
#[must_use]
|
||||
pub fn new(seed: u32) -> Self {
|
||||
let mut buf = [0u8; 16];
|
||||
lcg_urandom(seed, &mut buf);
|
||||
@@ -68,6 +69,7 @@ impl HashSecret {
|
||||
Ok(fix_sentinel(mod_int(hasher.finish() as PyHash)))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn hash_bytes(&self, value: &[u8]) -> PyHash {
|
||||
if value.is_empty() {
|
||||
0
|
||||
@@ -76,12 +78,14 @@ impl HashSecret {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn hash_str(&self, value: &str) -> PyHash {
|
||||
self.hash_bytes(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn hash_pointer(value: usize) -> PyHash {
|
||||
// TODO: 32bit?
|
||||
let hash = (value >> 4) | value;
|
||||
@@ -89,6 +93,7 @@ pub const fn hash_pointer(value: usize) -> PyHash {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn hash_float(value: f64) -> Option<PyHash> {
|
||||
// cpython _Py_HashDouble
|
||||
if !value.is_finite() {
|
||||
@@ -130,6 +135,7 @@ pub fn hash_float(value: f64) -> Option<PyHash> {
|
||||
Some(fix_sentinel(x as PyHash * value.signum() as PyHash))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn hash_bigint(value: &BigInt) -> PyHash {
|
||||
let ret = match value.to_i64() {
|
||||
Some(i) => mod_int(i),
|
||||
@@ -142,16 +148,19 @@ pub fn hash_bigint(value: &BigInt) -> PyHash {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn hash_usize(data: usize) -> PyHash {
|
||||
fix_sentinel(mod_int(data as i64))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const fn fix_sentinel(x: PyHash) -> PyHash {
|
||||
if x == SENTINEL { -2 } else { x }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn mod_int(value: i64) -> PyHash {
|
||||
value % MODULUS as i64
|
||||
}
|
||||
@@ -165,6 +174,7 @@ pub fn lcg_urandom(mut x: u32, buf: &mut [u8]) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn hash_object_id_raw(p: usize) -> PyHash {
|
||||
// TODO: Use commented logic when below issue resolved.
|
||||
// Ref: https://github.com/RustPython/RustPython/pull/3951#issuecomment-1193108966
|
||||
@@ -176,10 +186,12 @@ pub const fn hash_object_id_raw(p: usize) -> PyHash {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn hash_object_id(p: usize) -> PyHash {
|
||||
fix_sentinel(hash_object_id_raw(p))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn keyed_hash(key: u64, buf: &[u8]) -> u64 {
|
||||
let mut hasher = SipHasher24::new_with_keys(key, 0);
|
||||
buf.hash(&mut hasher);
|
||||
|
||||
@@ -3,6 +3,7 @@ use malachite_bigint::{BigInt, BigUint, Sign};
|
||||
use malachite_q::Rational;
|
||||
use num_traits::{One, ToPrimitive, Zero};
|
||||
|
||||
#[must_use]
|
||||
pub fn true_div(numerator: &BigInt, denominator: &BigInt) -> f64 {
|
||||
let rational = Rational::from_integers_ref(numerator.into(), denominator.into());
|
||||
match rational.rounding_into(RoundingMode::Nearest) {
|
||||
@@ -14,6 +15,7 @@ pub fn true_div(numerator: &BigInt, denominator: &BigInt) -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn float_to_ratio(value: f64) -> Option<(BigInt, BigInt)> {
|
||||
let sign = match core::cmp::PartialOrd::partial_cmp(&value, &0.0)? {
|
||||
core::cmp::Ordering::Less => Sign::Minus,
|
||||
@@ -146,6 +148,7 @@ pub fn bytes_to_int(
|
||||
|
||||
// num-bigint now returns Some(inf) for to_f64() in some cases, so just keep that the same for now
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn bigint_to_finite_float(int: &BigInt) -> Option<f64> {
|
||||
int.to_f64().filter(|f| f.is_finite())
|
||||
}
|
||||
|
||||
@@ -140,6 +140,7 @@ unsafe impl<T: Sync> Sync for Pointers<T> {}
|
||||
|
||||
impl<L, T> LinkedList<L, T> {
|
||||
/// Creates an empty linked list.
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
head: None,
|
||||
@@ -216,6 +217,7 @@ impl<L: Link> LinkedList<L, L::Target> {
|
||||
}
|
||||
|
||||
/// Returns whether the linked list does not contain any node
|
||||
#[must_use]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.head.is_none()
|
||||
// if self.head.is_some() {
|
||||
@@ -354,6 +356,7 @@ where
|
||||
|
||||
impl<T> Pointers<T> {
|
||||
/// Create a new set of empty pointers
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
inner: UnsafeCell::new(PointersInner {
|
||||
|
||||
@@ -35,12 +35,11 @@ impl<R: RawMutex, G: GetThreadId> RawThreadMutex<R, G> {
|
||||
let id = self.get_thread_id.nonzero_thread_id().get();
|
||||
if self.owner.load(Ordering::Relaxed) == id {
|
||||
return None;
|
||||
} else {
|
||||
if !try_lock() {
|
||||
return Some(false);
|
||||
}
|
||||
self.owner.store(id, Ordering::Relaxed);
|
||||
}
|
||||
if !try_lock() {
|
||||
return Some(false);
|
||||
}
|
||||
self.owner.store(id, Ordering::Relaxed);
|
||||
Some(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the OS entropy source returns an error.
|
||||
#[must_use]
|
||||
pub fn os_random<const N: usize>() -> [u8; N] {
|
||||
let mut buf = [0u8; N];
|
||||
getrandom::fill(&mut buf).unwrap();
|
||||
|
||||
@@ -86,6 +86,7 @@ impl Default for RefCount {
|
||||
|
||||
impl RefCount {
|
||||
/// Create a new RefCount with strong count = 1
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
// Initial state: strong=1, weak=1 (implicit weak for strong refs)
|
||||
Self {
|
||||
|
||||
@@ -67,10 +67,12 @@ mod non_threading {
|
||||
|
||||
impl<T> StaticCell<T> {
|
||||
#[doc(hidden)]
|
||||
#[must_use]
|
||||
pub const fn _from_local_key(inner: &'static LocalKey<OnceCell<&'static T>>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get(&'static self) -> Option<&'static T> {
|
||||
self.inner.with(|x| x.get().copied())
|
||||
}
|
||||
|
||||
@@ -36,15 +36,18 @@ impl core::ops::BitOr for StrKind {
|
||||
}
|
||||
|
||||
impl StrKind {
|
||||
#[must_use]
|
||||
pub const fn is_ascii(&self) -> bool {
|
||||
matches!(self, Self::Ascii)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_utf8(&self) -> bool {
|
||||
matches!(self, Self::Ascii | Self::Utf8)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn can_encode(&self, code: CodePoint) -> bool {
|
||||
match self {
|
||||
Self::Ascii => code.is_ascii(),
|
||||
@@ -234,6 +237,7 @@ impl StrData {
|
||||
/// # Safety
|
||||
///
|
||||
/// Given `bytes` must be valid data for given `kind`
|
||||
#[must_use]
|
||||
pub unsafe fn new_str_unchecked(data: Box<Wtf8>, kind: StrKind) -> Self {
|
||||
let len = match kind {
|
||||
StrKind::Ascii => data.len().into(),
|
||||
@@ -245,6 +249,7 @@ impl StrData {
|
||||
/// # Safety
|
||||
///
|
||||
/// `char_len` must be accurate.
|
||||
#[must_use]
|
||||
pub unsafe fn new_with_char_len(data: Box<Wtf8>, kind: StrKind, char_len: usize) -> Self {
|
||||
Self {
|
||||
data,
|
||||
@@ -364,6 +369,7 @@ pub fn get_chars(s: &str, range: impl RangeBounds<usize>) -> &str {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn char_range_end(s: &str, n_chars: usize) -> Option<usize> {
|
||||
let i = match n_chars.checked_sub(1) {
|
||||
Some(last_char_index) => {
|
||||
@@ -399,6 +405,7 @@ pub fn get_codepoints(w: &Wtf8, range: impl RangeBounds<usize>) -> &Wtf8 {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn codepoint_range_end(s: &Wtf8, n_chars: usize) -> Option<usize> {
|
||||
let i = match n_chars.checked_sub(1) {
|
||||
Some(last_char_index) => {
|
||||
@@ -410,6 +417,7 @@ pub fn codepoint_range_end(s: &Wtf8, n_chars: usize) -> Option<usize> {
|
||||
Some(i)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn zfill(bytes: &[u8], width: usize) -> Vec<u8> {
|
||||
if width <= bytes.len() {
|
||||
bytes.to_vec()
|
||||
@@ -428,6 +436,7 @@ pub fn zfill(bytes: &[u8], width: usize) -> Vec<u8> {
|
||||
|
||||
/// Convert a string to ascii compatible, escaping unicode-s into escape
|
||||
/// sequences.
|
||||
#[must_use]
|
||||
pub fn to_ascii(value: &Wtf8) -> AsciiString {
|
||||
let mut ascii = Vec::new();
|
||||
for cp in value.code_points() {
|
||||
@@ -485,6 +494,7 @@ pub mod levenshtein {
|
||||
if a == b { CASE_COST } else { MOVE_COST }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn levenshtein_distance(a: &[u8], b: &[u8], max_cost: usize) -> usize {
|
||||
if a == b {
|
||||
return 0;
|
||||
@@ -555,6 +565,7 @@ pub mod levenshtein {
|
||||
}
|
||||
|
||||
/// Replace all tabs in a string with spaces, using the given tab size.
|
||||
#[must_use]
|
||||
pub fn expandtabs(input: &str, tab_size: usize) -> String {
|
||||
let tab_stop = tab_size;
|
||||
let mut expanded_str = String::with_capacity(input.len());
|
||||
@@ -641,6 +652,7 @@ const UNICODE_DECIMAL_VALUES: &[char] = &[
|
||||
'𞥗', '𞥘', '𞥙',
|
||||
];
|
||||
|
||||
#[must_use]
|
||||
pub fn char_to_decimal(ch: char) -> Option<u8> {
|
||||
UNICODE_DECIMAL_VALUES
|
||||
.binary_search(&ch)
|
||||
|
||||
@@ -52,6 +52,7 @@ pub struct ExceptionTableEntry {
|
||||
}
|
||||
|
||||
impl ExceptionTableEntry {
|
||||
#[must_use]
|
||||
pub const fn new(start: u32, end: u32, target: u32, depth: u16, push_lasti: bool) -> Self {
|
||||
Self {
|
||||
start,
|
||||
@@ -65,6 +66,7 @@ impl ExceptionTableEntry {
|
||||
|
||||
/// Encode exception table entries.
|
||||
/// Uses 6-bit varint encoding with start marker (MSB) and continuation bit.
|
||||
#[must_use]
|
||||
pub fn encode_exception_table(entries: &[ExceptionTableEntry]) -> alloc::boxed::Box<[u8]> {
|
||||
let mut data = Vec::new();
|
||||
for entry in entries {
|
||||
@@ -80,6 +82,7 @@ pub fn encode_exception_table(entries: &[ExceptionTableEntry]) -> alloc::boxed::
|
||||
}
|
||||
|
||||
/// Find exception handler for given instruction offset.
|
||||
#[must_use]
|
||||
pub fn find_exception_handler(table: &[u8], offset: u32) -> Option<ExceptionTableEntry> {
|
||||
let mut pos = 0;
|
||||
while pos < table.len() {
|
||||
@@ -106,6 +109,7 @@ pub fn find_exception_handler(table: &[u8], offset: u32) -> Option<ExceptionTabl
|
||||
}
|
||||
|
||||
/// Decode all exception table entries.
|
||||
#[must_use]
|
||||
pub fn decode_exception_table(table: &[u8]) -> Vec<ExceptionTableEntry> {
|
||||
let mut entries = Vec::new();
|
||||
let mut pos = 0;
|
||||
@@ -138,6 +142,7 @@ pub fn decode_exception_table(table: &[u8]) -> Vec<ExceptionTableEntry> {
|
||||
|
||||
/// Parse linetable to build a boolean mask indicating which code units
|
||||
/// have NO_LOCATION (line == -1). Returns a Vec<bool> of length `num_units`.
|
||||
#[must_use]
|
||||
pub fn build_no_location_mask(linetable: &[u8], num_units: usize) -> Vec<bool> {
|
||||
let mut mask = Vec::new();
|
||||
mask.resize(num_units, false);
|
||||
@@ -227,6 +232,7 @@ pub enum PyCodeLocationInfoKind {
|
||||
}
|
||||
|
||||
impl PyCodeLocationInfoKind {
|
||||
#[must_use]
|
||||
pub fn from_code(code: u8) -> Option<Self> {
|
||||
match code {
|
||||
0 => Some(Self::Short0),
|
||||
@@ -249,10 +255,12 @@ impl PyCodeLocationInfoKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_short(&self) -> bool {
|
||||
(*self as u8) <= 9
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn short_column_group(&self) -> Option<u8> {
|
||||
if self.is_short() {
|
||||
Some(*self as u8)
|
||||
@@ -261,6 +269,7 @@ impl PyCodeLocationInfoKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn one_line_delta(&self) -> Option<i32> {
|
||||
match self {
|
||||
Self::OneLine0 => Some(0),
|
||||
@@ -483,24 +492,28 @@ const MAX_BACKOFF: u16 = 12;
|
||||
const UNREACHABLE_BACKOFF: u16 = 15;
|
||||
|
||||
/// Encode an adaptive counter as `(value << 4) | backoff`.
|
||||
#[must_use]
|
||||
pub const fn adaptive_counter_bits(value: u16, backoff: u16) -> u16 {
|
||||
(value << BACKOFF_BITS) | backoff
|
||||
}
|
||||
|
||||
/// True when the adaptive counter should trigger specialization.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn adaptive_counter_triggers(counter: u16) -> bool {
|
||||
counter < UNREACHABLE_BACKOFF
|
||||
}
|
||||
|
||||
/// Decrement adaptive counter by one countdown step.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn advance_adaptive_counter(counter: u16) -> u16 {
|
||||
counter.wrapping_sub(1 << BACKOFF_BITS)
|
||||
}
|
||||
|
||||
/// Reset adaptive counter with exponential backoff.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn adaptive_counter_backoff(counter: u16) -> u16 {
|
||||
let backoff = counter & ((1 << BACKOFF_BITS) - 1);
|
||||
if backoff < MAX_BACKOFF {
|
||||
@@ -511,6 +524,7 @@ pub const fn adaptive_counter_backoff(counter: u16) -> u16 {
|
||||
}
|
||||
|
||||
impl CodeUnit {
|
||||
#[must_use]
|
||||
pub const fn new(op: Instruction, arg: OpArgByte) -> Self {
|
||||
Self { op, arg }
|
||||
}
|
||||
@@ -1016,6 +1030,7 @@ impl<C: Constant> BorrowedConstant<'_, C> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn to_owned(self) -> ConstantData {
|
||||
use ConstantData::*;
|
||||
|
||||
|
||||
@@ -517,6 +517,7 @@ define_opcodes!(
|
||||
impl Instruction {
|
||||
/// Returns `true` if this is any instrumented opcode
|
||||
/// (regular INSTRUMENTED_*, INSTRUMENTED_LINE, or INSTRUMENTED_INSTRUCTION).
|
||||
#[must_use]
|
||||
pub const fn is_instrumented(self) -> bool {
|
||||
self.to_base().is_some()
|
||||
|| matches!(self, Self::InstrumentedLine | Self::InstrumentedInstruction)
|
||||
@@ -527,6 +528,7 @@ impl Instruction {
|
||||
///
|
||||
/// # Panics (debug)
|
||||
/// Panics if called on an already-instrumented opcode.
|
||||
#[must_use]
|
||||
pub fn to_instrumented(self) -> Option<Self> {
|
||||
debug_assert!(
|
||||
!self.is_instrumented(),
|
||||
@@ -564,6 +566,7 @@ impl Instruction {
|
||||
///
|
||||
/// The returned base opcode uses `Arg::marker()` for typed fields —
|
||||
/// only the opcode byte matters since `replace_op` preserves the arg byte.
|
||||
#[must_use]
|
||||
pub const fn to_base(self) -> Option<Self> {
|
||||
Some(match self {
|
||||
Self::InstrumentedResume => Self::Resume {
|
||||
@@ -613,6 +616,7 @@ impl Instruction {
|
||||
|
||||
/// Map a specialized opcode back to its adaptive (base) variant.
|
||||
/// `_PyOpcode_Deopt`
|
||||
#[must_use]
|
||||
pub const fn deopt(self) -> Option<Self> {
|
||||
let opcode = match self {
|
||||
Self::ResumeCheck => Opcode::Resume,
|
||||
@@ -696,6 +700,7 @@ impl Instruction {
|
||||
}
|
||||
|
||||
/// Map a specialized or instrumented opcode back to its adaptive (base) variant.
|
||||
#[must_use]
|
||||
pub const fn deoptimize(self) -> Self {
|
||||
match self.deopt() {
|
||||
Some(v) => v,
|
||||
@@ -714,6 +719,7 @@ impl Instruction {
|
||||
/// Instrumented and specialized opcodes have the same cache entries as their base.
|
||||
///
|
||||
/// _PyOpcode_Caches
|
||||
#[must_use]
|
||||
pub const fn cache_entries(self) -> usize {
|
||||
match self.deoptimize().opcode() {
|
||||
Opcode::LoadAttr => 9,
|
||||
@@ -1348,6 +1354,7 @@ impl PseudoInstruction {
|
||||
/// - [`PseudoInstruction::SetupCleanup`]
|
||||
/// - [`PseudoInstruction::SetupFinally`]
|
||||
/// - [`PseudoInstruction::SetupWith`]
|
||||
#[must_use]
|
||||
pub const fn is_block_push(&self) -> bool {
|
||||
matches!(
|
||||
self.opcode(),
|
||||
@@ -1530,6 +1537,7 @@ impl InstructionMetadata for AnyInstruction {
|
||||
|
||||
impl AnyInstruction {
|
||||
/// Inner value of [`Self::Real`].
|
||||
#[must_use]
|
||||
pub const fn real(self) -> Option<Instruction> {
|
||||
match self {
|
||||
Self::Real(ins) => Some(ins),
|
||||
@@ -1538,6 +1546,7 @@ impl AnyInstruction {
|
||||
}
|
||||
|
||||
/// Inner value of [`Self::Pseudo`].
|
||||
#[must_use]
|
||||
pub const fn pseudo(self) -> Option<PseudoInstruction> {
|
||||
match self {
|
||||
Self::Pseudo(ins) => Some(ins),
|
||||
@@ -1546,6 +1555,7 @@ impl AnyInstruction {
|
||||
}
|
||||
|
||||
/// Get [`Self::Real`] as [`Opcode`].
|
||||
#[must_use]
|
||||
pub const fn real_opcode(self) -> Option<Opcode> {
|
||||
match self.real() {
|
||||
Some(ins) => Some(ins.opcode()),
|
||||
@@ -1554,6 +1564,7 @@ impl AnyInstruction {
|
||||
}
|
||||
|
||||
/// Get [`Self::Pseudo`] as [`PseudoOpcode`].
|
||||
#[must_use]
|
||||
pub const fn pseudo_opcode(self) -> Option<PseudoOpcode> {
|
||||
match self.pseudo() {
|
||||
Some(ins) => Some(ins.opcode()),
|
||||
@@ -1566,6 +1577,7 @@ impl AnyInstruction {
|
||||
/// # Panics
|
||||
///
|
||||
/// If was called on something else other than [`Self::Real`].
|
||||
#[must_use]
|
||||
pub const fn expect_real(self) -> Instruction {
|
||||
self.real()
|
||||
.expect("Expected AnyInstruction::Real, found AnyInstruction::Pseudo")
|
||||
@@ -1576,17 +1588,20 @@ impl AnyInstruction {
|
||||
/// # Panics
|
||||
///
|
||||
/// If was called on something else other than [`Self::Pseudo`].
|
||||
#[must_use]
|
||||
pub const fn expect_pseudo(self) -> PseudoInstruction {
|
||||
self.pseudo()
|
||||
.expect("Expected AnyInstruction::Pseudo, found AnyInstruction::Real")
|
||||
}
|
||||
|
||||
/// Returns true if this is a [`PseudoInstruction::PopBlock`].
|
||||
#[must_use]
|
||||
pub const fn is_pop_block(self) -> bool {
|
||||
matches!(self, Self::Pseudo(PseudoInstruction::PopBlock))
|
||||
}
|
||||
|
||||
/// See [`PseudoInstruction::is_block_push`].
|
||||
#[must_use]
|
||||
pub const fn is_block_push(self) -> bool {
|
||||
matches!(self, Self::Pseudo(p) if p.is_block_push())
|
||||
}
|
||||
@@ -1640,6 +1655,7 @@ impl From<AnyInstruction> for AnyOpcode {
|
||||
|
||||
impl AnyOpcode {
|
||||
/// Gets the inner value of [`Self::Real`].
|
||||
#[must_use]
|
||||
pub const fn real(self) -> Option<Opcode> {
|
||||
match self {
|
||||
Self::Real(op) => Some(op),
|
||||
@@ -1648,6 +1664,7 @@ impl AnyOpcode {
|
||||
}
|
||||
|
||||
/// Gets the inner value of [`Self::Pseudo`].
|
||||
#[must_use]
|
||||
pub const fn pseudo(self) -> Option<PseudoOpcode> {
|
||||
match self {
|
||||
Self::Pseudo(op) => Some(op),
|
||||
@@ -1660,6 +1677,7 @@ impl AnyOpcode {
|
||||
/// # Panics
|
||||
///
|
||||
/// If was called on something else other than [`Self::Real`].
|
||||
#[must_use]
|
||||
pub const fn expect_real(self) -> Opcode {
|
||||
self.real()
|
||||
.expect("Expected AnyOpcode::Real, found AnyOpcode::Pseudo")
|
||||
@@ -1670,6 +1688,7 @@ impl AnyOpcode {
|
||||
/// # Panics
|
||||
///
|
||||
/// If was called on something else other than [`Self::Pseudo`].
|
||||
#[must_use]
|
||||
pub const fn expect_pseudo(self) -> PseudoOpcode {
|
||||
self.pseudo()
|
||||
.expect("Expected AnyOpcode::Pseudo, found AnyOpcode::Real")
|
||||
@@ -1687,21 +1706,25 @@ pub struct StackEffect {
|
||||
|
||||
impl StackEffect {
|
||||
/// Creates a new [`Self`].
|
||||
#[must_use]
|
||||
pub const fn new(pushed: u32, popped: u32) -> Self {
|
||||
Self { pushed, popped }
|
||||
}
|
||||
|
||||
/// Get the calculated stack effect as [`i32`].
|
||||
#[must_use]
|
||||
pub fn effect(self) -> i32 {
|
||||
self.into()
|
||||
}
|
||||
|
||||
/// Get the pushed count.
|
||||
#[must_use]
|
||||
pub const fn pushed(self) -> u32 {
|
||||
self.pushed
|
||||
}
|
||||
|
||||
/// Get the popped count.
|
||||
#[must_use]
|
||||
pub const fn popped(self) -> u32 {
|
||||
self.popped
|
||||
}
|
||||
@@ -1761,6 +1784,7 @@ pub struct Arg<T: OpArgType>(PhantomData<T>);
|
||||
|
||||
impl<T: OpArgType> Arg<T> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn marker() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
@@ -1779,6 +1803,7 @@ impl<T: OpArgType> Arg<T> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn get(self, arg: OpArg) -> T {
|
||||
self.try_get(arg).unwrap()
|
||||
}
|
||||
@@ -1791,6 +1816,7 @@ impl<T: OpArgType> Arg<T> {
|
||||
/// # Safety
|
||||
/// T::from_op_arg(self) must succeed
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub unsafe fn get_unchecked(self, arg: OpArg) -> T {
|
||||
// SAFETY: requirements forwarded from caller
|
||||
unsafe { T::try_from(u32::from(arg)).unwrap_unchecked() }
|
||||
|
||||
@@ -66,6 +66,7 @@ impl OpArg {
|
||||
|
||||
/// Returns how many CodeUnits a instruction with this op_arg will be encoded as
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn instr_size(self) -> usize {
|
||||
(self.0 > 0xff) as usize + (self.0 > 0xff_ff) as usize + (self.0 > 0xff_ff_ff) as usize + 1
|
||||
}
|
||||
|
||||
@@ -1138,6 +1138,7 @@ pub fn split_localplus<S: Clone>(
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn linetable_to_locations(
|
||||
linetable: &[u8],
|
||||
first_line: i32,
|
||||
|
||||
@@ -46,6 +46,7 @@ pub enum CompileError {
|
||||
}
|
||||
|
||||
impl CompileError {
|
||||
#[must_use]
|
||||
pub fn from_ruff_parse_error(error: parser::ParseError, source_file: &SourceFile) -> Self {
|
||||
let source_code = source_file.to_source_code();
|
||||
let source_text = source_file.source_text();
|
||||
@@ -116,6 +117,7 @@ impl CompileError {
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn location(&self) -> Option<SourceLocation> {
|
||||
match self {
|
||||
Self::Codegen(codegen_error) => codegen_error.location,
|
||||
@@ -123,6 +125,7 @@ impl CompileError {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn python_location(&self) -> (usize, usize) {
|
||||
if let Some(location) = self.location() {
|
||||
(location.line.get(), location.character_offset.get())
|
||||
@@ -131,6 +134,7 @@ impl CompileError {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn python_end_location(&self) -> Option<(usize, usize)> {
|
||||
match self {
|
||||
CompileError::Codegen(_) => None,
|
||||
@@ -141,6 +145,7 @@ impl CompileError {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn source_path(&self) -> &str {
|
||||
match self {
|
||||
Self::Codegen(codegen_error) => &codegen_error.source_path,
|
||||
|
||||
@@ -192,9 +192,8 @@ impl CompilationSource {
|
||||
let joined = path.parent().unwrap().join(real_path.trim());
|
||||
if joined.exists() {
|
||||
return compile_path(&joined);
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
Err(e)
|
||||
});
|
||||
|
||||
@@ -36,10 +36,12 @@ fn result_to_tokens(result: Result<TokenStream, impl Into<Diagnostic>>) -> Token
|
||||
.unwrap_or_else(ToTokens::into_token_stream)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn derive_from_args(input: DeriveInput) -> TokenStream {
|
||||
result_to_tokens(from_args::impl_from_args(input))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pyclass(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
if matches!(item, syn::Item::Impl(_) | syn::Item::Trait(_)) {
|
||||
result_to_tokens(pyclass::impl_pyclass_impl(attr, item))
|
||||
@@ -48,6 +50,7 @@ pub fn pyclass(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pyexception(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
if matches!(item, syn::Item::Impl(_)) {
|
||||
result_to_tokens(pyclass::impl_pyexception_impl(attr, item))
|
||||
@@ -56,14 +59,17 @@ pub fn pyexception(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pymodule(attr: PyModuleArgs, item: Item) -> TokenStream {
|
||||
result_to_tokens(pymodule::impl_pymodule(attr, item))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pystruct_sequence(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
result_to_tokens(pystructseq::impl_pystruct_sequence(attr, item))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pystruct_sequence_data(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
result_to_tokens(pystructseq::impl_pystruct_sequence_data(attr, item))
|
||||
}
|
||||
@@ -76,10 +82,12 @@ pub fn py_freeze(input: TokenStream, compiler: &dyn Compiler) -> TokenStream {
|
||||
result_to_tokens(compile_bytecode::impl_py_freeze(input, compiler))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pypayload(input: DeriveInput) -> TokenStream {
|
||||
result_to_tokens(pypayload::impl_pypayload(input))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pytraverse(item: DeriveInput) -> TokenStream {
|
||||
result_to_tokens(pytraverse::impl_pytraverse(item))
|
||||
}
|
||||
@@ -2014,9 +2014,8 @@ where
|
||||
Err(wrong_name) => {
|
||||
if ALL_ALLOWED_NAMES.contains(&attr_name.as_str()) {
|
||||
bail_span!(attr, "#[pyclass] doesn't accept #[{}]", wrong_name)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -469,9 +469,8 @@ where
|
||||
continue;
|
||||
} else if closed {
|
||||
bail_span!(attr, "Only one #[pyattr] annotated #[py*] item can exist")
|
||||
} else {
|
||||
bail_span!(attr, "#[pymodule] doesn't accept #[{}]", wrong_name)
|
||||
}
|
||||
bail_span!(attr, "#[pymodule] doesn't accept #[{}]", wrong_name)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -451,9 +451,8 @@ impl PyStructSequenceMeta {
|
||||
inner.meta_ident,
|
||||
"#[pystruct_sequence({KEY}=value)] expects a string value"
|
||||
)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) fn module(&self) -> Result<Option<String>> {
|
||||
@@ -475,9 +474,8 @@ impl PyStructSequenceMeta {
|
||||
inner.meta_ident,
|
||||
"#[pystruct_sequence({KEY}=value)] expects a string value"
|
||||
)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn data_type(&self) -> Result<Ident> {
|
||||
@@ -499,12 +497,11 @@ impl PyStructSequenceMeta {
|
||||
inner.meta_ident,
|
||||
"#[pystruct_sequence({KEY}=value)] expects a string value"
|
||||
)
|
||||
} else {
|
||||
bail_span!(
|
||||
inner.meta_ident,
|
||||
"#[pystruct_sequence] requires data parameter (e.g., data = \"DataStructName\")"
|
||||
)
|
||||
}
|
||||
bail_span!(
|
||||
inner.meta_ident,
|
||||
"#[pystruct_sequence] requires data parameter (e.g., data = \"DataStructName\")"
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn no_attr(&self) -> Result<bool> {
|
||||
|
||||
@@ -162,6 +162,7 @@ impl Owned {
|
||||
///
|
||||
/// `fd` must be a valid file descriptor.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub unsafe fn from_raw(fd: Raw) -> Self {
|
||||
let inner = unsafe { OwnedInner::from_raw_fd(fd) };
|
||||
Self { inner }
|
||||
@@ -184,20 +185,24 @@ impl Owned {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn borrow(&self) -> Borrowed<'_> {
|
||||
unsafe { Borrowed::borrow_raw(self.as_raw()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn as_raw(&self) -> Raw {
|
||||
self.inner.as_raw_fd()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_raw(self) -> Raw {
|
||||
self.inner.into_raw_fd()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn leak<'fd>(self) -> Borrowed<'fd> {
|
||||
unsafe { Borrowed::borrow_raw(self.into_raw()) }
|
||||
}
|
||||
@@ -252,6 +257,7 @@ impl<'fd> Borrowed<'fd> {
|
||||
///
|
||||
/// `fd` must be a valid file descriptor.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const unsafe fn borrow_raw(fd: Raw) -> Self {
|
||||
let inner = unsafe { BorrowedInner::borrow_raw(fd) };
|
||||
Self { inner }
|
||||
@@ -274,6 +280,7 @@ impl<'fd> Borrowed<'fd> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn as_raw(self) -> Raw {
|
||||
self.inner.as_raw_fd()
|
||||
}
|
||||
|
||||
@@ -352,6 +352,7 @@ pub mod windows {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn stat_basic_info_to_stat(info: &FILE_STAT_BASIC_INFORMATION) -> StatStruct {
|
||||
use windows_sys::Win32::Storage::FileSystem;
|
||||
use windows_sys::Win32::System::Ioctl;
|
||||
|
||||
@@ -29,10 +29,12 @@ pub fn setmode_binary(fd: crt_fd::Borrowed<'_>) {
|
||||
unsafe { suppress_iph!(_setmode(fd, libc::O_BINARY)) };
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn getch() -> Vec<u8> {
|
||||
vec![unsafe { _getch() } as u8]
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn getwch() -> String {
|
||||
let value = unsafe { _getwch() };
|
||||
char::from_u32(value)
|
||||
@@ -40,10 +42,12 @@ pub fn getwch() -> String {
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn getche() -> Vec<u8> {
|
||||
vec![unsafe { _getche() } as u8]
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn getwche() -> String {
|
||||
let value = unsafe { _getwche() };
|
||||
char::from_u32(value)
|
||||
@@ -77,6 +81,7 @@ pub fn ungetwch(c: char) -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn kbhit() -> i32 {
|
||||
unsafe { _kbhit() }
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use std::{
|
||||
///
|
||||
/// On Windows, this supports the full u32 range including STATUS_CONTROL_C_EXIT (0xC000013A).
|
||||
/// On other platforms, only the lower 8 bits are used.
|
||||
#[must_use]
|
||||
pub fn exit_code(code: u32) -> ExitCode {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
@@ -32,6 +33,7 @@ pub fn current_dir() -> io::Result<PathBuf> {
|
||||
env::current_dir()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn temp_dir() -> PathBuf {
|
||||
env::temp_dir()
|
||||
}
|
||||
@@ -44,10 +46,12 @@ pub fn var_os(key: impl AsRef<OsStr>) -> Option<OsString> {
|
||||
env::var_os(key)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn vars_os() -> env::VarsOs {
|
||||
env::vars_os()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn vars() -> env::Vars {
|
||||
env::vars()
|
||||
}
|
||||
@@ -70,6 +74,7 @@ pub fn set_current_dir(path: impl AsRef<std::path::Path>) -> io::Result<()> {
|
||||
env::set_current_dir(path)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn process_id() -> u32 {
|
||||
std::process::id()
|
||||
}
|
||||
@@ -97,6 +102,7 @@ impl ErrorExt for io::Error {
|
||||
/// Get the last error from C runtime library functions (like _dup, _dup2, _fstat, etc.)
|
||||
/// CRT functions set errno, not GetLastError(), so we need to read errno directly.
|
||||
#[cfg(windows)]
|
||||
#[must_use]
|
||||
pub fn errno_io_error() -> io::Error {
|
||||
let errno: i32 = get_errno();
|
||||
let winerror = errno_to_winerror(errno);
|
||||
@@ -104,6 +110,7 @@ pub fn errno_io_error() -> io::Error {
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[must_use]
|
||||
pub fn errno_io_error() -> io::Error {
|
||||
std::io::Error::last_os_error()
|
||||
}
|
||||
@@ -119,6 +126,7 @@ pub fn get_errno() -> i32 {
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[must_use]
|
||||
pub fn get_errno() -> i32 {
|
||||
std::io::Error::last_os_error().posix_errno()
|
||||
}
|
||||
@@ -206,6 +214,7 @@ pub mod ffi {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[must_use]
|
||||
pub fn errno_to_winerror(errno: i32) -> i32 {
|
||||
use libc::*;
|
||||
use windows_sys::Win32::Foundation::*;
|
||||
@@ -235,6 +244,7 @@ pub fn errno_to_winerror(errno: i32) -> i32 {
|
||||
// winerror: https://learn.microsoft.com/windows/win32/debug/system-error-codes--0-499-
|
||||
// errno: https://learn.microsoft.com/cpp/c-runtime-library/errno-constants?view=msvc-170
|
||||
#[cfg(windows)]
|
||||
#[must_use]
|
||||
pub fn winerror_to_errno(winerror: i32) -> i32 {
|
||||
use libc::*;
|
||||
use windows_sys::Win32::{
|
||||
|
||||
@@ -13,6 +13,7 @@ pub fn set_inheritable(fd: BorrowedFd<'_>, inheritable: bool) -> nix::Result<()>
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[must_use]
|
||||
pub fn get_number_of_os_threads() -> isize {
|
||||
type MachPortT = libc::c_uint;
|
||||
type KernReturnT = libc::c_int;
|
||||
@@ -60,6 +61,7 @@ pub fn get_number_of_os_threads() -> isize {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[must_use]
|
||||
pub fn get_number_of_os_threads() -> isize {
|
||||
use std::io::Read as _;
|
||||
|
||||
@@ -83,6 +85,7 @@ pub fn get_number_of_os_threads() -> isize {
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
#[must_use]
|
||||
pub fn get_number_of_os_threads() -> isize {
|
||||
0
|
||||
}
|
||||
@@ -119,6 +119,7 @@ pub use platform::{RawFd, timeval};
|
||||
pub struct FdSet(MaybeUninit<platform::fd_set>);
|
||||
|
||||
impl FdSet {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
let mut fdset = MaybeUninit::zeroed();
|
||||
unsafe { platform::FD_ZERO(fdset.as_mut_ptr()) };
|
||||
@@ -177,6 +178,7 @@ pub fn select(
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn sec_to_timeval(sec: f64) -> timeval {
|
||||
timeval {
|
||||
tv_sec: sec.trunc() as _,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#[must_use]
|
||||
pub fn timeval_to_double(tv: &libc::timeval) -> f64 {
|
||||
tv.tv_sec as f64 + (tv.tv_usec as f64 / 1_000_000.0)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn double_to_timeval(val: f64) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: val.trunc() as _,
|
||||
@@ -9,6 +11,7 @@ pub fn double_to_timeval(val: f64) -> libc::timeval {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn itimerval_to_tuple(it: &libc::itimerval) -> (f64, f64) {
|
||||
(
|
||||
timeval_to_double(&it.it_value),
|
||||
|
||||
@@ -25,6 +25,7 @@ fn global_ident() -> &'static RwLock<Option<GlobalIdent>> {
|
||||
IDENT.get_or_init(|| RwLock::new(None))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_open() -> bool {
|
||||
global_ident()
|
||||
.read()
|
||||
@@ -55,14 +56,17 @@ pub fn closelog() {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn setlogmask(maskpri: i32) -> i32 {
|
||||
unsafe { libc::setlogmask(maskpri) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn log_mask(pri: i32) -> i32 {
|
||||
pri << 1
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn log_upto(pri: i32) -> i32 {
|
||||
(1 << (pri + 1)) - 1
|
||||
}
|
||||
@@ -16,6 +16,7 @@ pub fn duration_since_system_now() -> Result<Duration, SystemTimeError> {
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[must_use]
|
||||
pub fn get_tz_info() -> windows_sys::Win32::System::Time::TIME_ZONE_INFORMATION {
|
||||
let mut info = unsafe { core::mem::zeroed() };
|
||||
unsafe { windows_sys::Win32::System::Time::GetTimeZoneInformation(&mut info) };
|
||||
@@ -23,6 +24,7 @@ pub fn get_tz_info() -> windows_sys::Win32::System::Time::TIME_ZONE_INFORMATION
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
#[must_use]
|
||||
pub fn asctime_from_tm(tm: &libc::tm) -> String {
|
||||
const WDAY_NAME: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
const MON_NAME: [&str; 12] = [
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
use windows_sys::Win32::Foundation::HANDLE;
|
||||
|
||||
#[must_use]
|
||||
pub fn get_acp() -> u32 {
|
||||
unsafe { windows_sys::Win32::Globalization::GetACP() }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_current_process() -> HANDLE {
|
||||
unsafe { windows_sys::Win32::System::Threading::GetCurrentProcess() }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_last_error() -> u32 {
|
||||
unsafe { windows_sys::Win32::Foundation::GetLastError() }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_version() -> u32 {
|
||||
unsafe { windows_sys::Win32::System::SystemInformation::GetVersion() }
|
||||
}
|
||||
@@ -335,8 +335,9 @@ pub struct ArgsBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ArgsBuilder<'a> {
|
||||
fn new(code: &'a CompiledCode) -> ArgsBuilder<'a> {
|
||||
ArgsBuilder {
|
||||
#[must_use]
|
||||
fn new(code: &'a CompiledCode) -> Self {
|
||||
Self {
|
||||
values: vec![None; code.sig.args.len()],
|
||||
code,
|
||||
}
|
||||
@@ -348,10 +349,12 @@ impl<'a> ArgsBuilder<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_set(&self, idx: usize) -> bool {
|
||||
self.values[idx].is_some()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn into_args(self) -> Option<Args<'a>> {
|
||||
// Ensure all values are set
|
||||
if self.values.iter().any(|v| v.is_none()) {
|
||||
@@ -370,6 +373,7 @@ pub struct Args<'a> {
|
||||
}
|
||||
|
||||
impl Args<'_> {
|
||||
#[must_use]
|
||||
pub fn invoke(&self) -> Option<AbiValue> {
|
||||
let cif_args: Vec<_> = self.values.iter().map(AbiValue::to_libffi_arg).collect();
|
||||
unsafe { self.code.invoke_raw(&cif_args) }
|
||||
|
||||
@@ -60,6 +60,7 @@ impl Default for Marks {
|
||||
}
|
||||
|
||||
impl Marks {
|
||||
#[must_use]
|
||||
pub fn get(&self, group_index: usize) -> (Optioned<usize>, Optioned<usize>) {
|
||||
let marks_index = 2 * group_index;
|
||||
if marks_index + 1 < self.marks.len() {
|
||||
@@ -69,10 +70,12 @@ impl Marks {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn last_index(&self) -> isize {
|
||||
self.last_index
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn raw(&self) -> &[Optioned<usize>] {
|
||||
self.marks.as_slice()
|
||||
}
|
||||
@@ -191,9 +194,8 @@ impl State {
|
||||
if flags.contains(SreInfo::PREFIX) {
|
||||
if flags.contains(SreInfo::LITERAL) {
|
||||
return search_info_literal::<true, S>(&mut req, self, ctx);
|
||||
} else {
|
||||
return search_info_literal::<false, S>(&mut req, self, ctx);
|
||||
}
|
||||
return search_info_literal::<false, S>(&mut req, self, ctx);
|
||||
} else if flags.contains(SreInfo::CHARSET) {
|
||||
return search_info_charset(&mut req, self, ctx);
|
||||
}
|
||||
@@ -432,10 +434,9 @@ fn _match<S: StrDrive>(req: &Request<'_, S>, state: &mut State, mut ctx: MatchCo
|
||||
if max_count == MAXREPEAT || ctx.count as usize <= max_count {
|
||||
state.cursor = ctx.cursor;
|
||||
break 'context ctx.next_peek_from(1, req, Jump::MinRepeatOne2);
|
||||
} else {
|
||||
state.marks.pop_discard();
|
||||
break 'result false;
|
||||
}
|
||||
state.marks.pop_discard();
|
||||
break 'result false;
|
||||
}
|
||||
Jump::MinRepeatOne2 => {
|
||||
if popped_result {
|
||||
@@ -485,10 +486,9 @@ fn _match<S: StrDrive>(req: &Request<'_, S>, state: &mut State, mut ctx: MatchCo
|
||||
ctx.count += 1;
|
||||
ctx.jump = Jump::PossessiveRepeat1;
|
||||
continue 'context;
|
||||
} else {
|
||||
state.cursor = ctx.cursor;
|
||||
break 'result false;
|
||||
}
|
||||
state.cursor = ctx.cursor;
|
||||
break 'result false;
|
||||
}
|
||||
Jump::PossessiveRepeat3 => {
|
||||
let max_count = ctx.peek_code(req, 3) as usize;
|
||||
|
||||
@@ -372,6 +372,7 @@ pub(crate) const fn is_linebreak(ch: u32) -> bool {
|
||||
ch == '\n' as u32
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn lower_ascii(ch: u32) -> u32 {
|
||||
u8::try_from(ch)
|
||||
.map(|x| x.to_ascii_lowercase() as u32)
|
||||
@@ -456,6 +457,7 @@ pub(crate) fn is_uni_word(ch: u32) -> bool {
|
||||
ch == '_' as u32 || is_uni_alnum(ch)
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn lower_unicode(ch: u32) -> u32 {
|
||||
// TODO: check with cpython
|
||||
char::try_from(ch)
|
||||
@@ -463,6 +465,7 @@ pub fn lower_unicode(ch: u32) -> u32 {
|
||||
.unwrap_or(ch)
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn upper_unicode(ch: u32) -> u32 {
|
||||
// TODO: check with cpython
|
||||
char::try_from(ch)
|
||||
|
||||
@@ -457,7 +457,7 @@ mod _sqlite3 {
|
||||
let db = context.db_handle();
|
||||
let args = args
|
||||
.iter()
|
||||
.cloned()
|
||||
.copied()
|
||||
.map(|val| value_to_object(val, db, vm))
|
||||
.collect::<PyResult<Vec<PyObjectRef>>>()?;
|
||||
|
||||
@@ -654,7 +654,7 @@ mod _sqlite3 {
|
||||
let db = context.db_handle();
|
||||
let args = args
|
||||
.iter()
|
||||
.cloned()
|
||||
.copied()
|
||||
.map(|val| value_to_object(val, db, vm))
|
||||
.collect::<PyResult<Vec<PyObjectRef>>>()?;
|
||||
vm.call_method(instance, name, args).map(drop)
|
||||
@@ -680,7 +680,9 @@ mod _sqlite3 {
|
||||
|
||||
impl Drop for CallbackData {
|
||||
fn drop(&mut self) {
|
||||
unsafe { PyObjectRef::from_raw(self.obj) };
|
||||
unsafe {
|
||||
let _ = PyObjectRef::from_raw(self.obj);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,10 +162,9 @@ pub(crate) fn _decompress_chunks<D: Decompressor>(
|
||||
} else if !chunk.is_empty() && consumed == 0 {
|
||||
// we're gonna need a bigger buffer
|
||||
continue;
|
||||
} else {
|
||||
// next chunk
|
||||
continue 'outer;
|
||||
}
|
||||
// next chunk
|
||||
continue 'outer;
|
||||
}
|
||||
Err(e) => {
|
||||
d.maybe_set_dict(e)?;
|
||||
|
||||
@@ -1012,7 +1012,7 @@ mod decl {
|
||||
|
||||
pub(super) fn get_user_signal(signum: usize) -> Option<UserSignal> {
|
||||
let guard = USER_SIGNALS.lock();
|
||||
guard.as_ref().and_then(|v| v.get(signum).cloned())
|
||||
guard.as_ref().and_then(|v| v.get(signum).copied())
|
||||
}
|
||||
|
||||
pub(super) fn set_user_signal(signum: usize, signal: UserSignal) {
|
||||
|
||||
@@ -47,7 +47,7 @@ mod decl {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use crate::vm::class::PyClassImpl;
|
||||
poll::PyPoll::make_static_type();
|
||||
let _ = poll::PyPoll::make_static_type();
|
||||
}
|
||||
|
||||
__module_exec(vm, module);
|
||||
|
||||
@@ -818,10 +818,9 @@ impl<'a> CertLoader<'a> {
|
||||
return Err(cert_error::der::not_enough_data(
|
||||
"cadata does not contain a certificate",
|
||||
));
|
||||
} else {
|
||||
// Loaded some certificates but failed on subsequent data (garbage)
|
||||
return Err(cert_error::der::parse_failed(e));
|
||||
}
|
||||
// Loaded some certificates but failed on subsequent data (garbage)
|
||||
return Err(cert_error::der::parse_failed(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2018,30 +2018,28 @@ fn ssl_read_tls_records(
|
||||
if is_bio {
|
||||
// In BIO mode, no data means WANT_READ
|
||||
return Err(SslError::WantRead);
|
||||
} else {
|
||||
// In socket mode, empty recv() means TCP EOF (FIN received)
|
||||
// Need to distinguish:
|
||||
// 1. Clean shutdown: received TLS close_notify → return ZeroReturn (0 bytes)
|
||||
// 2. Unexpected EOF: no close_notify → return Eof (SSLEOFError)
|
||||
//
|
||||
// SSL_ERROR_ZERO_RETURN vs SSL_ERROR_EOF logic
|
||||
// CPython checks SSL_get_shutdown() & SSL_RECEIVED_SHUTDOWN
|
||||
//
|
||||
// Process any buffered TLS records (may contain close_notify)
|
||||
match conn.process_new_packets() {
|
||||
Ok(io_state) => {
|
||||
if io_state.peer_has_closed() {
|
||||
// Received close_notify - normal SSL closure (SSL_ERROR_ZERO_RETURN)
|
||||
return Err(SslError::ZeroReturn);
|
||||
} else {
|
||||
// No close_notify - ragged EOF (SSL_ERROR_EOF → SSLEOFError)
|
||||
// CPython raises SSLEOFError here, which SSLSocket.read() handles
|
||||
// based on suppress_ragged_eofs setting
|
||||
return Err(SslError::Eof);
|
||||
}
|
||||
}
|
||||
// In socket mode, empty recv() means TCP EOF (FIN received)
|
||||
// Need to distinguish:
|
||||
// 1. Clean shutdown: received TLS close_notify → return ZeroReturn (0 bytes)
|
||||
// 2. Unexpected EOF: no close_notify → return Eof (SSLEOFError)
|
||||
//
|
||||
// SSL_ERROR_ZERO_RETURN vs SSL_ERROR_EOF logic
|
||||
// CPython checks SSL_get_shutdown() & SSL_RECEIVED_SHUTDOWN
|
||||
//
|
||||
// Process any buffered TLS records (may contain close_notify)
|
||||
match conn.process_new_packets() {
|
||||
Ok(io_state) => {
|
||||
if io_state.peer_has_closed() {
|
||||
// Received close_notify - normal SSL closure (SSL_ERROR_ZERO_RETURN)
|
||||
return Err(SslError::ZeroReturn);
|
||||
}
|
||||
Err(e) => return Err(SslError::from_rustls(e)),
|
||||
// No close_notify - ragged EOF (SSL_ERROR_EOF → SSLEOFError)
|
||||
// CPython raises SSLEOFError here, which SSLSocket.read() handles
|
||||
// based on suppress_ragged_eofs setting
|
||||
return Err(SslError::Eof);
|
||||
}
|
||||
Err(e) => return Err(SslError::from_rustls(e)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -523,6 +523,7 @@ impl FormatSpec {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ impl PyAsyncGen {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn new(frame: FrameRef, name: PyStrRef, qualname: PyStrRef) -> Self {
|
||||
Self {
|
||||
inner: Coro::new(frame, name, qualname),
|
||||
|
||||
@@ -205,16 +205,19 @@ impl PyRef<PyBytes> {
|
||||
)]
|
||||
impl PyBytes {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn __len__(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
self.inner.as_bytes()
|
||||
}
|
||||
|
||||
@@ -272,10 +272,12 @@ impl PyComplex {
|
||||
Self::from(value).into_ref(ctx)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn to_complex64(self) -> Complex64 {
|
||||
self.value
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn to_complex(&self) -> Complex64 {
|
||||
self.value
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ impl PyCoroutine {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn new(frame: FrameRef, name: PyStrRef, qualname: PyStrRef) -> Self {
|
||||
Self {
|
||||
inner: Coro::new(frame, name, qualname),
|
||||
|
||||
@@ -29,6 +29,7 @@ pub struct PyFloat {
|
||||
}
|
||||
|
||||
impl PyFloat {
|
||||
#[must_use]
|
||||
pub const fn to_f64(&self) -> f64 {
|
||||
self.value
|
||||
}
|
||||
|
||||
@@ -1261,6 +1261,7 @@ impl Constructor for PyBoundMethod {
|
||||
}
|
||||
|
||||
impl PyBoundMethod {
|
||||
#[must_use]
|
||||
pub const fn new(object: PyObjectRef, function: PyObjectRef) -> Self {
|
||||
Self { object, function }
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ impl PyGenerator {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn new(frame: FrameRef, name: PyStrRef, qualname: PyStrRef) -> Self {
|
||||
Self {
|
||||
inner: Coro::new(frame, name, qualname),
|
||||
|
||||
@@ -303,12 +303,14 @@ impl PyInt {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn as_bigint(&self) -> &BigInt {
|
||||
&self.value
|
||||
}
|
||||
|
||||
/// Fast decimal string conversion, using i64 path when possible.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn to_str_radix_10(&self) -> String {
|
||||
match self.value.to_i64() {
|
||||
Some(i) => i.to_string(),
|
||||
@@ -317,6 +319,7 @@ impl PyInt {
|
||||
}
|
||||
|
||||
// _PyLong_AsUnsignedLongMask
|
||||
#[must_use]
|
||||
pub fn as_u32_mask(&self) -> u32 {
|
||||
let v = self.as_bigint();
|
||||
v.to_u32()
|
||||
|
||||
@@ -239,6 +239,7 @@ impl PyPayload for PyCallableIterator {
|
||||
|
||||
#[pyclass(with(IterNext, Iterable))]
|
||||
impl PyCallableIterator {
|
||||
#[must_use]
|
||||
pub const fn new(callable: ArgCallable, sentinel: PyObjectRef) -> Self {
|
||||
Self {
|
||||
sentinel,
|
||||
|
||||
@@ -113,6 +113,7 @@ pub struct ModuleInitArgs {
|
||||
|
||||
impl PyModule {
|
||||
#[allow(clippy::new_without_default)]
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
def: None,
|
||||
@@ -120,6 +121,7 @@ impl PyModule {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn from_def(def: &'static PyModuleDef) -> Self {
|
||||
Self {
|
||||
def: Some(def),
|
||||
|
||||
@@ -128,6 +128,7 @@ impl PyRange {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn index_of(&self, value: &BigInt) -> Option<BigInt> {
|
||||
let step = self.step.as_bigint();
|
||||
match self.offset(value) {
|
||||
@@ -137,16 +138,19 @@ impl PyRange {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.compute_length().is_zero()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn forward(&self) -> bool {
|
||||
self.start.as_bigint() < self.stop.as_bigint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn get(&self, index: &BigInt) -> Option<BigInt> {
|
||||
let start = self.start.as_bigint();
|
||||
let step = self.step.as_bigint();
|
||||
|
||||
@@ -46,6 +46,7 @@ impl PySet {
|
||||
Self::default().into_ref(ctx)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn elements(&self) -> Vec<PyObjectRef> {
|
||||
self.inner.elements()
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ impl Constructor for PyStaticMethod {
|
||||
}
|
||||
|
||||
impl PyStaticMethod {
|
||||
#[must_use]
|
||||
pub fn new(callable: PyObjectRef) -> Self {
|
||||
Self {
|
||||
callable: PyMutex::new(callable),
|
||||
|
||||
@@ -456,6 +456,7 @@ impl PyStr {
|
||||
|
||||
/// # Safety
|
||||
/// Given `bytes` must be ascii
|
||||
#[must_use]
|
||||
pub unsafe fn new_ascii_unchecked(bytes: Vec<u8>) -> Self {
|
||||
unsafe { AsciiString::from_ascii_unchecked(bytes) }.into()
|
||||
}
|
||||
@@ -1533,6 +1534,7 @@ impl PyStr {
|
||||
}
|
||||
|
||||
impl PyRef<PyStr> {
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
(**self).is_empty()
|
||||
}
|
||||
@@ -2221,6 +2223,7 @@ impl Py<PyUtf8Str> {
|
||||
|
||||
impl PyRef<PyUtf8Str> {
|
||||
/// Convert to PyStrRef. Safe because PyUtf8Str is a subtype of PyStr.
|
||||
#[must_use]
|
||||
pub fn into_wtf8(self) -> PyStrRef {
|
||||
unsafe { mem::transmute::<Self, PyStrRef>(self) }
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ impl PyPayload for PyTemplate {
|
||||
}
|
||||
|
||||
impl PyTemplate {
|
||||
#[must_use]
|
||||
pub fn new(strings: PyTupleRef, interpolations: PyTupleRef) -> Self {
|
||||
Self {
|
||||
strings,
|
||||
|
||||
@@ -28,6 +28,7 @@ impl PyPayload for PyTraceback {
|
||||
|
||||
#[pyclass(with(Constructor))]
|
||||
impl PyTraceback {
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
next: Option<PyRef<Self>>,
|
||||
frame: FrameRef,
|
||||
|
||||
@@ -291,16 +291,19 @@ impl<'a, R> core::iter::IntoIterator for &'a Py<PyTuple<R>> {
|
||||
}
|
||||
|
||||
impl<R> PyTuple<R> {
|
||||
#[must_use]
|
||||
pub const fn as_slice(&self) -> &[R] {
|
||||
&self.elements
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.elements.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.elements.is_empty()
|
||||
}
|
||||
@@ -325,6 +328,7 @@ impl PyTuple<PyObjectRef> {
|
||||
/// Creating a new tuple with given boxed slice.
|
||||
/// NOTE: for usual case, you probably want to use PyTuple::new_ref.
|
||||
/// Calling this function implies trying micro optimization for non-zero-sized tuple.
|
||||
#[must_use]
|
||||
pub const fn new_unchecked(elements: Box<[PyObjectRef]>) -> Self {
|
||||
Self { elements }
|
||||
}
|
||||
@@ -402,6 +406,7 @@ impl PyTuple {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn __len__(&self) -> usize {
|
||||
self.elements.len()
|
||||
}
|
||||
@@ -608,6 +613,7 @@ impl PyRef<PyTuple<PyObjectRef>> {
|
||||
}
|
||||
|
||||
impl<T: PyPayload> PyRef<PyTuple<PyRef<T>>> {
|
||||
#[must_use]
|
||||
pub fn into_untyped(self) -> PyRef<PyTuple> {
|
||||
// SAFETY: PyTuple<PyRef<T>> has the same layout as PyTuple
|
||||
unsafe { core::mem::transmute::<Self, PyRef<PyTuple>>(self) }
|
||||
|
||||
@@ -53,6 +53,7 @@ impl PyUnion {
|
||||
|
||||
/// Direct access to args field (_Py_union_args)
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn args(&self) -> &Py<PyTuple> {
|
||||
&self.args
|
||||
}
|
||||
|
||||
@@ -67,14 +67,17 @@ pub trait StaticType {
|
||||
// Ideally, saving PyType is better than PyTypeRef
|
||||
fn static_cell() -> &'static static_cell::StaticCell<PyTypeRef>;
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn static_metaclass() -> &'static Py<PyType> {
|
||||
PyType::static_type()
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn static_baseclass() -> &'static Py<PyType> {
|
||||
PyBaseObject::static_type()
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn static_type() -> &'static Py<PyType> {
|
||||
#[cold]
|
||||
fn fail() -> ! {
|
||||
@@ -84,12 +87,14 @@ pub trait StaticType {
|
||||
}
|
||||
Self::static_cell().get().unwrap_or_else(|| fail())
|
||||
}
|
||||
#[must_use]
|
||||
fn init_manually(typ: PyTypeRef) -> &'static Py<PyType> {
|
||||
let cell = Self::static_cell();
|
||||
cell.set(typ)
|
||||
.unwrap_or_else(|_| panic!("double initialization from init_manually"));
|
||||
cell.get().unwrap()
|
||||
}
|
||||
#[must_use]
|
||||
fn init_builtin_type() -> &'static Py<PyType>
|
||||
where
|
||||
Self: PyClassImpl,
|
||||
@@ -100,6 +105,7 @@ pub trait StaticType {
|
||||
.unwrap_or_else(|_| panic!("double initialization of {}", Self::NAME));
|
||||
cell.get().unwrap()
|
||||
}
|
||||
#[must_use]
|
||||
fn create_static_type() -> PyTypeRef
|
||||
where
|
||||
Self: PyClassImpl,
|
||||
@@ -206,6 +212,7 @@ pub trait PyClassImpl: PyClassDef {
|
||||
class.extend_methods(class.slots.methods, ctx);
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn make_static_type() -> PyTypeRef
|
||||
where
|
||||
Self: StaticType + Sized,
|
||||
|
||||
@@ -59,6 +59,7 @@ pub struct DataStack {
|
||||
|
||||
impl DataStack {
|
||||
/// Create a new data stack with an initial root chunk.
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
let chunk = Self::alloc_chunk(MIN_CHUNK_SIZE, ptr::null_mut());
|
||||
let top = unsafe { (*chunk).data_start() };
|
||||
@@ -71,6 +72,7 @@ impl DataStack {
|
||||
|
||||
/// Check if the current chunk has at least `size` bytes available.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn has_space(&self, size: usize) -> bool {
|
||||
let aligned_size = (size + ALIGN - 1) & !(ALIGN - 1);
|
||||
(self.limit as usize).saturating_sub(self.top as usize) >= aligned_size
|
||||
|
||||
@@ -34,6 +34,7 @@ fn create_exception_group(ctx: &Context) -> PyRef<PyType> {
|
||||
.expect("Failed to create ExceptionGroup type with multiple inheritance")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn exception_group() -> &'static Py<PyType> {
|
||||
::rustpython_vm::common::static_cell! {
|
||||
static CELL: ::rustpython_vm::builtins::PyTypeRef;
|
||||
|
||||
@@ -139,6 +139,7 @@ impl FuncArgs {
|
||||
/// `args[..nargs]` are positional, and if `kwnames` is provided,
|
||||
/// the last `kwnames.len()` entries in `args[nargs..]` are keyword values.
|
||||
/// Convert borrowed vectorcall args to FuncArgs (clones all values).
|
||||
#[must_use]
|
||||
pub fn from_vectorcall(
|
||||
args: &[PyObjectRef],
|
||||
nargs: usize,
|
||||
@@ -170,6 +171,7 @@ impl FuncArgs {
|
||||
}
|
||||
|
||||
/// Convert owned vectorcall args to FuncArgs (moves values, no clone).
|
||||
#[must_use]
|
||||
pub fn from_vectorcall_owned(
|
||||
mut args: Vec<PyObjectRef>,
|
||||
nargs: usize,
|
||||
@@ -198,6 +200,7 @@ impl FuncArgs {
|
||||
Self { args, kwargs }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.args.is_empty() && self.kwargs.is_empty()
|
||||
}
|
||||
@@ -211,6 +214,7 @@ impl FuncArgs {
|
||||
self.args.remove(0)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_kwarg(&self, key: &str, default: PyObjectRef) -> PyObjectRef {
|
||||
self.kwargs
|
||||
.get(key)
|
||||
@@ -218,6 +222,7 @@ impl FuncArgs {
|
||||
.unwrap_or_else(|| default.clone())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_optional_kwarg(&self, key: &str) -> Option<PyObjectRef> {
|
||||
self.kwargs.get(key).cloned()
|
||||
}
|
||||
@@ -357,6 +362,7 @@ pub trait FromArgs: Sized {
|
||||
/// The range of positional arguments permitted by the function signature.
|
||||
///
|
||||
/// Returns an empty range if not applicable.
|
||||
#[must_use]
|
||||
fn arity() -> RangeInclusive<usize> {
|
||||
0..=0
|
||||
}
|
||||
@@ -411,6 +417,7 @@ where
|
||||
}
|
||||
|
||||
impl<T> KwArgs<T> {
|
||||
#[must_use]
|
||||
pub const fn new(map: IndexMap<String, T>) -> Self {
|
||||
Self(map)
|
||||
}
|
||||
@@ -419,6 +426,7 @@ impl<T> KwArgs<T> {
|
||||
self.0.swap_remove(name)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_empty(self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
@@ -479,10 +487,12 @@ where
|
||||
}
|
||||
|
||||
impl<T> PosArgs<T> {
|
||||
#[must_use]
|
||||
pub const fn new(args: Vec<T>) -> Self {
|
||||
Self(args)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
self.0
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ impl PyObject {
|
||||
}
|
||||
|
||||
impl ArgBytesLike {
|
||||
#[must_use]
|
||||
pub fn borrow_buf(&self) -> BorrowedValue<'_, [u8]> {
|
||||
unsafe { self.0.contiguous_unchecked() }
|
||||
}
|
||||
@@ -50,14 +51,17 @@ impl ArgBytesLike {
|
||||
f(&self.borrow_buf())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn len(&self) -> usize {
|
||||
self.0.desc.len
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_object(&self) -> &PyObject {
|
||||
&self.0.obj
|
||||
}
|
||||
@@ -91,6 +95,7 @@ impl<'a> TryFromBorrowedObject<'a> for ArgBytesLike {
|
||||
pub struct ArgMemoryBuffer(PyBuffer);
|
||||
|
||||
impl ArgMemoryBuffer {
|
||||
#[must_use]
|
||||
pub fn borrow_buf_mut(&self) -> BorrowedValueMut<'_, [u8]> {
|
||||
unsafe { self.0.contiguous_mut_unchecked() }
|
||||
}
|
||||
@@ -102,10 +107,12 @@ impl ArgMemoryBuffer {
|
||||
f(&mut self.borrow_buf_mut())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn len(&self) -> usize {
|
||||
self.0.desc.len
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
@@ -137,6 +144,7 @@ pub enum ArgStrOrBytesLike {
|
||||
}
|
||||
|
||||
impl ArgStrOrBytesLike {
|
||||
#[must_use]
|
||||
pub fn as_object(&self) -> &PyObject {
|
||||
match self {
|
||||
Self::Buf(b) => b.as_object(),
|
||||
@@ -154,6 +162,7 @@ impl TryFromObject for ArgStrOrBytesLike {
|
||||
}
|
||||
|
||||
impl ArgStrOrBytesLike {
|
||||
#[must_use]
|
||||
pub fn borrow_bytes(&self) -> BorrowedValue<'_, [u8]> {
|
||||
match self {
|
||||
Self::Buf(b) => b.borrow_buf(),
|
||||
@@ -184,6 +193,7 @@ impl TryFromObject for ArgAsciiBuffer {
|
||||
}
|
||||
|
||||
impl ArgAsciiBuffer {
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Self::String(s) => s.as_wtf8().len(),
|
||||
@@ -191,6 +201,7 @@ impl ArgAsciiBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ impl FsPath {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
// TODO: FS encodings
|
||||
match self {
|
||||
@@ -97,6 +98,7 @@ impl FsPath {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn to_string_lossy(&self) -> Cow<'_, str> {
|
||||
match self {
|
||||
Self::Str(s) => s.to_string_lossy(),
|
||||
|
||||
@@ -118,6 +118,7 @@ impl PyMethodDef {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn to_function(&'static self) -> PyNativeFunction {
|
||||
PyNativeFunction {
|
||||
zelf: None,
|
||||
@@ -226,6 +227,7 @@ impl PyMethodDef {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[must_use]
|
||||
pub const fn __const_concat_arrays<const SUM_LEN: usize>(
|
||||
method_groups: &[&[Self]],
|
||||
) -> [Self; SUM_LEN] {
|
||||
@@ -286,6 +288,7 @@ pub struct HeapMethodDef {
|
||||
}
|
||||
|
||||
impl HeapMethodDef {
|
||||
#[must_use]
|
||||
pub const fn new(method: PyMethodDef) -> Self {
|
||||
Self { method }
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ pub struct ArgIntoComplex {
|
||||
|
||||
impl ArgIntoComplex {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_complex(self) -> Complex64 {
|
||||
self.value
|
||||
}
|
||||
@@ -60,10 +61,12 @@ pub struct ArgIntoFloat {
|
||||
|
||||
impl ArgIntoFloat {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_float(self) -> f64 {
|
||||
self.value
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn vec_into_f64(v: Vec<Self>) -> Vec<f64> {
|
||||
// TODO: Vec::into_raw_parts once stabilized
|
||||
let mut v = core::mem::ManuallyDrop::new(v);
|
||||
@@ -105,6 +108,7 @@ impl ArgIntoBool {
|
||||
pub const FALSE: Self = Self { value: false };
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_bool(self) -> bool {
|
||||
self.value
|
||||
}
|
||||
@@ -133,6 +137,7 @@ pub struct ArgIndex {
|
||||
|
||||
impl ArgIndex {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_int_ref(self) -> PyIntRef {
|
||||
self.value
|
||||
}
|
||||
|
||||
@@ -124,21 +124,25 @@ pub struct ArgMapping {
|
||||
|
||||
impl ArgMapping {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn new(obj: PyObjectRef) -> Self {
|
||||
Self { obj }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn from_dict_exact(dict: PyDictRef) -> Self {
|
||||
Self { obj: dict.into() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn obj(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn mapping(&self) -> PyMapping<'_> {
|
||||
self.obj.mapping_unchecked()
|
||||
}
|
||||
@@ -191,10 +195,12 @@ unsafe impl<T: Traverse> Traverse for ArgSequence<T> {
|
||||
|
||||
impl<T> ArgSequence<T> {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
self.0
|
||||
}
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
@@ -10,11 +10,13 @@ pub struct TimeoutSeconds {
|
||||
}
|
||||
|
||||
impl TimeoutSeconds {
|
||||
#[must_use]
|
||||
pub const fn new(secs: f64) -> Self {
|
||||
Self { value: secs }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn to_secs_f64(self) -> f64 {
|
||||
self.value
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ pub struct GcGeneration {
|
||||
}
|
||||
|
||||
impl GcGeneration {
|
||||
#[must_use]
|
||||
pub const fn new(threshold: u32) -> Self {
|
||||
Self {
|
||||
count: AtomicUsize::new(0),
|
||||
@@ -174,6 +175,7 @@ impl Default for GcState {
|
||||
}
|
||||
|
||||
impl GcState {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
generations: [
|
||||
|
||||
@@ -63,13 +63,12 @@ macro_rules! py_namespace {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use malachite_bigint::ToBigInt;
|
||||
/// use num_traits::Zero;
|
||||
///
|
||||
/// use rustpython_vm::match_class;
|
||||
/// use rustpython_vm::{PyPayload, match_class};
|
||||
/// use rustpython_vm::builtins::{PyFloat, PyInt};
|
||||
/// use rustpython_vm::{PyPayload};
|
||||
///
|
||||
/// # rustpython_vm::Interpreter::without_stdlib(Default::default()).enter(|vm| {
|
||||
/// let obj = PyInt::from(0).into_pyobject(vm);
|
||||
@@ -87,13 +86,12 @@ macro_rules! py_namespace {
|
||||
///
|
||||
/// With a binding to the downcasted type:
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use malachite_bigint::ToBigInt;
|
||||
/// use num_traits::Zero;
|
||||
///
|
||||
/// use rustpython_vm::match_class;
|
||||
/// use rustpython_vm::{PyPayload, match_class};
|
||||
/// use rustpython_vm::builtins::{PyFloat, PyInt};
|
||||
/// use rustpython_vm::{ PyPayload};
|
||||
///
|
||||
/// # rustpython_vm::Interpreter::without_stdlib(Default::default()).enter(|vm| {
|
||||
/// let obj = PyInt::from(0).into_pyobject(vm);
|
||||
|
||||
@@ -1291,6 +1291,7 @@ impl PyObject {
|
||||
|
||||
impl PyObjectRef {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const fn into_raw(self) -> NonNull<PyObject> {
|
||||
let ptr = self.ptr;
|
||||
core::mem::forget(self);
|
||||
@@ -1303,6 +1304,7 @@ impl PyObjectRef {
|
||||
/// dropped more than once due to mishandling the reference count by calling this function
|
||||
/// too many times.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const unsafe fn from_raw(ptr: NonNull<PyObject>) -> Self {
|
||||
Self { ptr }
|
||||
}
|
||||
@@ -1330,6 +1332,7 @@ impl PyObjectRef {
|
||||
/// # Safety
|
||||
/// T must be the exact payload type
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub unsafe fn downcast_unchecked<T>(self) -> PyRef<T> {
|
||||
// PyRef::from_obj_unchecked(self)
|
||||
// manual impl to avoid assertion
|
||||
@@ -1926,6 +1929,7 @@ impl PyStackRef {
|
||||
/// Create an owned stack reference, consuming the `PyObjectRef`.
|
||||
/// Refcount is NOT incremented — ownership is transferred.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn new_owned(obj: PyObjectRef) -> Self {
|
||||
let ptr = obj.into_raw();
|
||||
let bits = ptr.as_ptr() as usize;
|
||||
@@ -1957,12 +1961,14 @@ impl PyStackRef {
|
||||
|
||||
/// Whether this is a borrowed (non-owning) reference.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_borrowed(&self) -> bool {
|
||||
self.bits.get() & STACKREF_BORROW_TAG != 0
|
||||
}
|
||||
|
||||
/// Get a `&PyObject` reference. Works for both owned and borrowed.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn as_object(&self) -> &PyObject {
|
||||
unsafe { &*((self.bits.get() & !STACKREF_BORROW_TAG) as *const PyObject) }
|
||||
}
|
||||
@@ -1972,6 +1978,7 @@ impl PyStackRef {
|
||||
/// * If **borrowed** → increments refcount, forgets self.
|
||||
/// * If **owned** → reconstructs `PyObjectRef` from the raw pointer, forgets self.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn to_pyobj(self) -> PyObjectRef {
|
||||
let obj = if self.is_borrowed() {
|
||||
self.as_object().to_owned() // inc refcount
|
||||
@@ -2213,6 +2220,7 @@ impl<T: PyPayload> PyRef<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn leak(pyref: Self) -> &'static Py<T> {
|
||||
let ptr = pyref.ptr;
|
||||
core::mem::forget(pyref);
|
||||
@@ -2281,6 +2289,7 @@ where
|
||||
/// # Safety
|
||||
/// T and T::Base must have compatible layouts in size_of::<T::Base>() bytes.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_base(self) -> PyRef<T::Base> {
|
||||
let obj: PyObjectRef = self.into();
|
||||
match obj.downcast() {
|
||||
@@ -2289,6 +2298,7 @@ where
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn upcast<U: PyPayload + StaticType>(self) -> PyRef<U>
|
||||
where
|
||||
T: StaticType,
|
||||
@@ -2404,6 +2414,7 @@ pub struct PyWeakRef<T: PyPayload> {
|
||||
}
|
||||
|
||||
impl<T: PyPayload> PyWeakRef<T> {
|
||||
#[must_use]
|
||||
pub fn upgrade(&self) -> Option<PyRef<T>> {
|
||||
self.weak
|
||||
.upgrade()
|
||||
|
||||
@@ -142,10 +142,12 @@ pub struct PyRefExact<T: PyPayload> {
|
||||
impl<T: PyPayload> PyRefExact<T> {
|
||||
/// # Safety
|
||||
/// obj must have exact type for the payload
|
||||
#[must_use]
|
||||
pub const unsafe fn new_unchecked(obj: PyRef<T>) -> Self {
|
||||
Self { inner: obj }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn into_pyref(self) -> PyRef<T> {
|
||||
self.inner
|
||||
}
|
||||
@@ -500,6 +502,7 @@ unsafe impl Send for PyAtomicBorrow {}
|
||||
unsafe impl Sync for PyAtomicBorrow {}
|
||||
|
||||
impl PyAtomicBorrow {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Radium::new(null_mut()),
|
||||
@@ -610,6 +613,7 @@ pub struct PyLease<'a, T: PyPayload> {
|
||||
|
||||
impl<T: PyPayload> PyLease<'_, T> {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn into_owned(self) -> PyRef<T> {
|
||||
self.inner.clone()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ pub struct PathConverter {
|
||||
}
|
||||
|
||||
impl PathConverter {
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
function_name: None,
|
||||
@@ -29,16 +30,19 @@ impl PathConverter {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn function(mut self, name: &'static str) -> Self {
|
||||
self.function_name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn argument(mut self, name: &'static str) -> Self {
|
||||
self.argument_name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn non_strict(mut self) -> Self {
|
||||
self.non_strict = true;
|
||||
self
|
||||
@@ -235,14 +239,17 @@ impl OsPath {
|
||||
Self::from_fspath(fspath, vm)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_path(&self) -> &Path {
|
||||
Path::new(&self.path)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
self.path.into_encoded_bytes()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn to_string_lossy(&self) -> alloc::borrow::Cow<'_, str> {
|
||||
self.path.to_string_lossy()
|
||||
}
|
||||
@@ -266,6 +273,7 @@ impl OsPath {
|
||||
}
|
||||
|
||||
/// Get the output mode based on origin type (bytes -> Bytes, otherwise -> String)
|
||||
#[must_use]
|
||||
pub fn mode(&self) -> OutputMode {
|
||||
match &self.origin {
|
||||
Some(obj) if obj.downcast_ref::<PyBytes>().is_some() => OutputMode::Bytes,
|
||||
|
||||
@@ -42,6 +42,7 @@ pub struct PyBuffer {
|
||||
}
|
||||
|
||||
impl PyBuffer {
|
||||
#[must_use]
|
||||
pub fn new(obj: PyObjectRef, desc: BufferDescriptor, methods: &'static BufferMethods) -> Self {
|
||||
let zelf = Self {
|
||||
obj,
|
||||
@@ -52,12 +53,14 @@ impl PyBuffer {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_contiguous(&self) -> Option<BorrowedValue<'_, [u8]>> {
|
||||
self.desc
|
||||
.is_contiguous()
|
||||
.then(|| unsafe { self.contiguous_unchecked() })
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_contiguous_mut(&self) -> Option<BorrowedValueMut<'_, [u8]>> {
|
||||
(!self.desc.readonly && self.desc.is_contiguous())
|
||||
.then(|| unsafe { self.contiguous_mut_unchecked() })
|
||||
@@ -74,12 +77,14 @@ impl PyBuffer {
|
||||
|
||||
/// # Safety
|
||||
/// assume the buffer is contiguous
|
||||
#[must_use]
|
||||
pub unsafe fn contiguous_unchecked(&self) -> BorrowedValue<'_, [u8]> {
|
||||
self.obj_bytes()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// assume the buffer is contiguous and writable
|
||||
#[must_use]
|
||||
pub unsafe fn contiguous_mut_unchecked(&self) -> BorrowedValueMut<'_, [u8]> {
|
||||
self.obj_bytes_mut()
|
||||
}
|
||||
@@ -109,14 +114,17 @@ impl PyBuffer {
|
||||
f(v)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn obj_as<T: PyObjectPayload>(&self) -> &Py<T> {
|
||||
unsafe { self.obj.downcast_unchecked_ref() }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn obj_bytes(&self) -> BorrowedValue<'_, [u8]> {
|
||||
(self.methods.obj_bytes)(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn obj_bytes_mut(&self) -> BorrowedValueMut<'_, [u8]> {
|
||||
(self.methods.obj_bytes_mut)(self)
|
||||
}
|
||||
@@ -174,6 +182,7 @@ pub struct BufferDescriptor {
|
||||
}
|
||||
|
||||
impl BufferDescriptor {
|
||||
#[must_use]
|
||||
pub fn simple(bytes_len: usize, readonly: bool) -> Self {
|
||||
Self {
|
||||
len: bytes_len,
|
||||
@@ -184,6 +193,7 @@ impl BufferDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn format(
|
||||
bytes_len: usize,
|
||||
readonly: bool,
|
||||
@@ -200,6 +210,7 @@ impl BufferDescriptor {
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[must_use]
|
||||
pub fn validate(self) -> Self {
|
||||
// ndim=0 is valid for scalar types (e.g., ctypes Structure)
|
||||
if self.ndim() == 0 {
|
||||
@@ -211,7 +222,7 @@ impl BufferDescriptor {
|
||||
} else {
|
||||
let mut shape_product = 1;
|
||||
let has_zero_dim = self.dim_desc.iter().any(|(s, _, _)| *s == 0);
|
||||
for (shape, stride, suboffset) in self.dim_desc.iter().cloned() {
|
||||
for (shape, stride, suboffset) in self.dim_desc.iter().copied() {
|
||||
shape_product *= shape;
|
||||
assert!(suboffset >= 0);
|
||||
// For empty arrays (any dimension is 0), strides can be 0
|
||||
@@ -229,16 +240,18 @@ impl BufferDescriptor {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn ndim(&self) -> usize {
|
||||
self.dim_desc.len()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_contiguous(&self) -> bool {
|
||||
if self.len == 0 {
|
||||
return true;
|
||||
}
|
||||
let mut sd = self.itemsize;
|
||||
for (shape, stride, _) in self.dim_desc.iter().cloned().rev() {
|
||||
for (shape, stride, _) in self.dim_desc.iter().copied().rev() {
|
||||
if shape > 1 && stride != sd as isize {
|
||||
return false;
|
||||
}
|
||||
@@ -249,12 +262,13 @@ impl BufferDescriptor {
|
||||
|
||||
/// this function do not check the bound
|
||||
/// panic if indices.len() != ndim
|
||||
#[must_use]
|
||||
pub fn fast_position(&self, indices: &[usize]) -> isize {
|
||||
let mut pos = 0;
|
||||
for (i, (_, stride, suboffset)) in indices
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip_eq(self.dim_desc.iter().cloned())
|
||||
.copied()
|
||||
.zip_eq(self.dim_desc.iter().copied())
|
||||
{
|
||||
pos += i as isize * stride + suboffset;
|
||||
}
|
||||
@@ -266,8 +280,8 @@ impl BufferDescriptor {
|
||||
let mut pos = 0;
|
||||
for (i, (shape, stride, suboffset)) in indices
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip_eq(self.dim_desc.iter().cloned())
|
||||
.copied()
|
||||
.zip_eq(self.dim_desc.iter().copied())
|
||||
{
|
||||
let i = i.wrapped_at(shape).ok_or_else(|| {
|
||||
vm.new_index_error(format!("index out of bounds on dimension {i}"))
|
||||
@@ -387,6 +401,7 @@ impl BufferDescriptor {
|
||||
suboffset == 0 && stride == self.itemsize as isize
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_zero_in_shape(&self) -> bool {
|
||||
self.dim_desc.iter().any(|(shape, _, _)| *shape == 0)
|
||||
}
|
||||
@@ -428,6 +443,7 @@ impl From<Vec<u8>> for VecBuffer {
|
||||
}
|
||||
|
||||
impl PyRef<VecBuffer> {
|
||||
#[must_use]
|
||||
pub fn into_pybuffer(self, readonly: bool) -> PyBuffer {
|
||||
let len = self.data.lock().len();
|
||||
PyBuffer::new(
|
||||
@@ -437,6 +453,7 @@ impl PyRef<VecBuffer> {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn into_pybuffer_with_descriptor(self, desc: BufferDescriptor) -> PyBuffer {
|
||||
PyBuffer::new(self.into(), desc, &VEC_BUFFER_METHODS)
|
||||
}
|
||||
|
||||
@@ -105,11 +105,13 @@ impl AsRef<PyObject> for PyMapping<'_> {
|
||||
|
||||
impl PyMapping<'_> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn slots(&self) -> &PyMappingSlots {
|
||||
&self.obj.class().slots.as_mapping
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn check(&self) -> bool {
|
||||
self.slots().has_subscript()
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ impl PyNumberMethods {
|
||||
inplace_matrix_multiply: None,
|
||||
};
|
||||
|
||||
#[must_use]
|
||||
pub fn not_implemented() -> &'static Self {
|
||||
static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED;
|
||||
&GLOBAL_NOT_IMPLEMENTED
|
||||
@@ -612,6 +613,7 @@ impl<'a> PyNumber<'a> {
|
||||
|
||||
impl PyNumber<'_> {
|
||||
// PyIndex_Check
|
||||
#[must_use]
|
||||
pub fn is_index(self) -> bool {
|
||||
self.class().slots.as_number.index.load().is_some()
|
||||
}
|
||||
|
||||
@@ -131,10 +131,12 @@ unsafe impl Traverse for PySequence<'_> {
|
||||
|
||||
impl PySequence<'_> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn slots(&self) -> &PySequenceSlots {
|
||||
&self.obj.class().slots.as_sequence
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn check(&self) -> bool {
|
||||
self.slots().has_item()
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ impl fmt::Debug for Scope {
|
||||
|
||||
impl Scope {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn new(locals: Option<ArgMapping>, globals: PyDictRef) -> Self {
|
||||
Self { locals, globals }
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ impl fmt::Display for UserSignalSendError {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user_signal_channel() -> (UserSignalSender, UserSignalReceiver) {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
(UserSignalSender { tx }, UserSignalReceiver { rx })
|
||||
|
||||
@@ -369,6 +369,7 @@ impl SaturatedSlice {
|
||||
// Equivalent to PySlice_AdjustIndices
|
||||
/// Convert for usage in indexing the underlying rust collections. Called *after*
|
||||
/// __index__ has been called on the Slice which might mutate the collection.
|
||||
#[must_use]
|
||||
pub fn adjust_indices(&self, len: usize) -> (Range<usize>, isize, usize) {
|
||||
if len == 0 {
|
||||
return (0..0, self.step, 0);
|
||||
@@ -398,6 +399,7 @@ impl SaturatedSlice {
|
||||
(range, self.step, slice_len)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn iter(&self, len: usize) -> SaturatedSliceIter {
|
||||
SaturatedSliceIter::new(self, len)
|
||||
}
|
||||
@@ -410,11 +412,13 @@ pub struct SaturatedSliceIter {
|
||||
}
|
||||
|
||||
impl SaturatedSliceIter {
|
||||
#[must_use]
|
||||
pub fn new(slice: &SaturatedSlice, seq_len: usize) -> Self {
|
||||
let (range, step, len) = slice.adjust_indices(seq_len);
|
||||
Self::from_adjust_indices(range, step, len)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn from_adjust_indices(range: Range<usize>, step: isize, len: usize) -> Self {
|
||||
let index = if step.is_negative() {
|
||||
range.end as isize - 1
|
||||
@@ -424,6 +428,7 @@ impl SaturatedSliceIter {
|
||||
Self { index, step, len }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn positive_order(mut self) -> Self {
|
||||
if self.step.is_negative() {
|
||||
self.index += self.step * self.len.saturating_sub(1) as isize;
|
||||
|
||||
@@ -1304,13 +1304,13 @@ pub(crate) mod _ctypes {
|
||||
__module_exec(vm, module);
|
||||
|
||||
let ctx = &vm.ctx;
|
||||
PyCSimpleType::make_static_type();
|
||||
array::PyCArrayType::make_static_type();
|
||||
pointer::PyCPointerType::make_static_type();
|
||||
structure::PyCStructType::make_static_type();
|
||||
union::PyCUnionType::make_static_type();
|
||||
function::PyCFuncPtrType::make_static_type();
|
||||
function::RawMemoryBuffer::make_static_type();
|
||||
let _ = PyCSimpleType::make_static_type();
|
||||
let _ = array::PyCArrayType::make_static_type();
|
||||
let _ = pointer::PyCPointerType::make_static_type();
|
||||
let _ = structure::PyCStructType::make_static_type();
|
||||
let _ = union::PyCUnionType::make_static_type();
|
||||
let _ = function::PyCFuncPtrType::make_static_type();
|
||||
let _ = function::RawMemoryBuffer::make_static_type();
|
||||
|
||||
extend_module!(vm, module, {
|
||||
"_CData" => PyCData::make_static_type(),
|
||||
|
||||
@@ -66,7 +66,7 @@ mod _sre {
|
||||
impl SreStr for &[u8] {
|
||||
fn slice(&self, start: usize, end: usize, vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.ctx
|
||||
.new_bytes(self.iter().take(end).skip(start).cloned().collect())
|
||||
.new_bytes(self.iter().take(end).skip(start).copied().collect())
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +315,7 @@ pub(crate) mod _thread {
|
||||
|
||||
/// Get thread identity - uses pthread_self() on Unix for fork compatibility
|
||||
#[pyfunction]
|
||||
#[must_use]
|
||||
pub fn get_ident() -> u64 {
|
||||
current_thread_id()
|
||||
}
|
||||
|
||||
@@ -1346,7 +1346,7 @@ mod builtins {
|
||||
pub fn init_module(vm: &VirtualMachine, module: &Py<PyModule>) {
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
crate::protocol::VecBuffer::make_static_type();
|
||||
let _ = crate::protocol::VecBuffer::make_static_type();
|
||||
|
||||
module.__init_methods(vm).unwrap();
|
||||
builtins::module_exec(vm, module).unwrap();
|
||||
|
||||
@@ -37,6 +37,7 @@ impl TypeDataSlot {
|
||||
}
|
||||
|
||||
/// Get a reference to the data if the type matches.
|
||||
#[must_use]
|
||||
pub fn get<T: Any + 'static>(&self) -> Option<&T> {
|
||||
if self.type_id == TypeId::of::<T>() {
|
||||
self.data.downcast_ref()
|
||||
@@ -63,6 +64,7 @@ pub struct TypeDataRef<'a, T: 'static> {
|
||||
impl<'a, T: Any + 'static> TypeDataRef<'a, T> {
|
||||
/// Try to create a TypeDataRef from a read guard.
|
||||
/// Returns None if the slot is empty or contains a different type.
|
||||
#[must_use]
|
||||
pub fn try_new(guard: PyRwLockReadGuard<'a, Option<TypeDataSlot>>) -> Option<Self> {
|
||||
PyRwLockReadGuard::try_map(guard, |opt| opt.as_ref().and_then(|slot| slot.get::<T>()))
|
||||
.ok()
|
||||
@@ -86,6 +88,7 @@ pub struct TypeDataRefMut<'a, T: 'static> {
|
||||
impl<'a, T: Any + 'static> TypeDataRefMut<'a, T> {
|
||||
/// Try to create a TypeDataRefMut from a write guard.
|
||||
/// Returns None if the slot is empty or contains a different type.
|
||||
#[must_use]
|
||||
pub fn try_new(guard: PyRwLockWriteGuard<'a, Option<TypeDataSlot>>) -> Option<Self> {
|
||||
PyRwLockWriteGuard::try_map(guard, |opt| {
|
||||
opt.as_mut().and_then(|slot| slot.get_mut::<T>())
|
||||
@@ -188,6 +191,7 @@ pub struct PyTypeSlots {
|
||||
}
|
||||
|
||||
impl PyTypeSlots {
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str, flags: PyTypeFlags) -> Self {
|
||||
Self {
|
||||
name,
|
||||
@@ -196,6 +200,7 @@ impl PyTypeSlots {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn heap_default() -> Self {
|
||||
Self {
|
||||
// init: AtomicCell::new(Some(init_wrapper)),
|
||||
@@ -243,6 +248,7 @@ impl PyTypeFlags {
|
||||
// CPython: See initialization of flags in type_new.
|
||||
/// Used for types created in Python. Subclassable and are a
|
||||
/// heaptype.
|
||||
#[must_use]
|
||||
pub const fn heap_type_flags() -> Self {
|
||||
match Self::from_bits(Self::DEFAULT.bits() | Self::HEAPTYPE.bits() | Self::BASETYPE.bits())
|
||||
{
|
||||
@@ -251,11 +257,13 @@ impl PyTypeFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_feature(self, flag: Self) -> bool {
|
||||
self.contains(flag)
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[must_use]
|
||||
pub const fn is_created_with_flags(self) -> bool {
|
||||
self.contains(Self::_CREATED_WITH_FLAGS)
|
||||
}
|
||||
@@ -1862,6 +1870,7 @@ impl PyComparisonOp {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn eval_ord(self, ord: Ordering) -> bool {
|
||||
match self {
|
||||
Self::Lt => ord == Ordering::Less,
|
||||
@@ -1873,6 +1882,7 @@ impl PyComparisonOp {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn swapped(self) -> Self {
|
||||
match self {
|
||||
Self::Lt => Self::Gt,
|
||||
@@ -1895,6 +1905,7 @@ impl PyComparisonOp {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn operator_token(self) -> &'static str {
|
||||
match self {
|
||||
Self::Lt => "<",
|
||||
@@ -1987,6 +1998,7 @@ pub trait AsMapping: PyPayload {
|
||||
fn as_mapping() -> &'static PyMappingMethods;
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn mapping_downcast(mapping: PyMapping<'_>) -> &Py<Self> {
|
||||
unsafe { mapping.obj.downcast_unchecked_ref() }
|
||||
}
|
||||
@@ -2001,6 +2013,7 @@ pub trait AsSequence: PyPayload {
|
||||
fn as_sequence() -> &'static PySequenceMethods;
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn sequence_downcast(seq: PySequence<'_>) -> &Py<Self> {
|
||||
unsafe { seq.obj.downcast_unchecked_ref() }
|
||||
}
|
||||
@@ -2025,6 +2038,7 @@ pub trait AsNumber: PyPayload {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn number_downcast(num: PyNumber<'_>) -> &Py<Self> {
|
||||
unsafe { num.obj.downcast_unchecked_ref() }
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ pub enum SlotOp {
|
||||
|
||||
impl SlotOp {
|
||||
/// Convert to PyComparisonOp if this is a comparison operation
|
||||
#[must_use]
|
||||
pub fn as_compare_op(&self) -> Option<PyComparisonOp> {
|
||||
match self {
|
||||
Self::Lt => Some(PyComparisonOp::Lt),
|
||||
@@ -41,6 +42,7 @@ impl SlotOp {
|
||||
}
|
||||
|
||||
/// Check if this is a right operation (__radd__, __rsub__, etc.)
|
||||
#[must_use]
|
||||
pub fn is_right(&self) -> bool {
|
||||
matches!(self, Self::Right)
|
||||
}
|
||||
@@ -167,6 +169,7 @@ pub enum SlotAccessor {
|
||||
|
||||
impl SlotAccessor {
|
||||
/// Check if this accessor is for a reserved/unused slot
|
||||
#[must_use]
|
||||
pub fn is_reserved(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
@@ -195,6 +198,7 @@ impl SlotAccessor {
|
||||
}
|
||||
|
||||
/// Check if this is a number binary operation slot
|
||||
#[must_use]
|
||||
pub fn is_number_binary(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
@@ -223,6 +227,7 @@ impl SlotAccessor {
|
||||
/// - TpDescrSet: __set__ and __delete__
|
||||
/// - SqAssItem/MpAssSubscript: __setitem__ and __delitem__
|
||||
/// - Number binaries: __add__ and __radd__, etc.
|
||||
#[must_use]
|
||||
pub fn is_shared_slot(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
@@ -235,6 +240,7 @@ impl SlotAccessor {
|
||||
}
|
||||
|
||||
/// Get underlying slot field name for debugging
|
||||
#[must_use]
|
||||
pub fn slot_name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::BfGetBuffer => "bf_getbuffer",
|
||||
@@ -322,6 +328,7 @@ impl SlotAccessor {
|
||||
}
|
||||
|
||||
/// Extract the raw function pointer from a SlotFunc if it matches this accessor's type
|
||||
#[must_use]
|
||||
pub fn extract_from_slot_func(&self, slot_func: &SlotFunc) -> bool {
|
||||
match self {
|
||||
// Type slots
|
||||
|
||||
@@ -15,6 +15,7 @@ pub const SERIAL: usize = 0;
|
||||
pub const VERSION_HEX: usize =
|
||||
(MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL;
|
||||
|
||||
#[must_use]
|
||||
pub fn get_version() -> String {
|
||||
// Windows: include MSC v. for compatibility with ctypes.util.find_library
|
||||
// MSC v.1929 = VS 2019, version 14+ makes find_msvcrt() return None
|
||||
@@ -42,16 +43,19 @@ pub fn get_version() -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_version_number() -> String {
|
||||
format!("{MAJOR}.{MINOR}.{MICRO}{RELEASELEVEL}")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_winver_number() -> String {
|
||||
format!("{MAJOR}.{MINOR}")
|
||||
}
|
||||
|
||||
const COMPILER: &str = env!("RUSTC_VERSION");
|
||||
|
||||
#[must_use]
|
||||
pub fn get_build_info() -> String {
|
||||
// See: https://reproducible-builds.org/docs/timestamps/
|
||||
let git_revision = get_git_revision();
|
||||
@@ -73,20 +77,24 @@ pub fn get_build_info() -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_git_revision() -> String {
|
||||
option_env!("RUSTPYTHON_GIT_HASH").unwrap_or("").to_owned()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_git_tag() -> String {
|
||||
option_env!("RUSTPYTHON_GIT_TAG").unwrap_or("").to_owned()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_git_branch() -> String {
|
||||
option_env!("RUSTPYTHON_GIT_BRANCH")
|
||||
.unwrap_or("")
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_git_identifier() -> String {
|
||||
let git_tag = get_git_tag();
|
||||
let git_branch = get_git_branch();
|
||||
@@ -109,18 +117,21 @@ fn get_git_timestamp_datetime() -> DateTime<Local> {
|
||||
datetime.into()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_git_date() -> String {
|
||||
let datetime = get_git_timestamp_datetime();
|
||||
|
||||
datetime.format("%b %e %Y").to_string()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_git_time() -> String {
|
||||
let datetime = get_git_timestamp_datetime();
|
||||
|
||||
datetime.format("%H:%M:%S").to_string()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_git_datetime() -> String {
|
||||
let date = get_git_date();
|
||||
let time = get_git_time();
|
||||
|
||||
@@ -288,6 +288,7 @@ impl Context {
|
||||
pub const INT_CACHE_POOL_RANGE: core::ops::RangeInclusive<i32> = (-5)..=256;
|
||||
const INT_CACHE_POOL_MIN: i32 = *Self::INT_CACHE_POOL_RANGE.start();
|
||||
|
||||
#[must_use]
|
||||
pub fn genesis() -> &'static PyRc<Self> {
|
||||
rustpython_common::static_cell! {
|
||||
static CONTEXT: PyRc<Context>;
|
||||
|
||||
@@ -155,6 +155,7 @@ where
|
||||
|
||||
impl InterpreterBuilder {
|
||||
/// Create a new interpreter configuration with default settings.
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
settings: Settings::default(),
|
||||
@@ -168,6 +169,7 @@ impl InterpreterBuilder {
|
||||
/// Set custom settings for the interpreter.
|
||||
///
|
||||
/// If called multiple times, only the last settings will be used.
|
||||
#[must_use]
|
||||
pub fn settings(mut self, settings: Settings) -> Self {
|
||||
self.settings = settings;
|
||||
self
|
||||
@@ -185,6 +187,7 @@ impl InterpreterBuilder {
|
||||
/// // let interp = builder.add_native_module(def).build();
|
||||
/// let interp = builder.build();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn add_native_module(self, def: &'static builtins::PyModuleDef) -> Self {
|
||||
self.add_native_modules(&[def])
|
||||
}
|
||||
@@ -201,6 +204,7 @@ impl InterpreterBuilder {
|
||||
/// // let interp = builder.add_native_modules(&defs).build();
|
||||
/// let interp = builder.build();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn add_native_modules(mut self, defs: &[&'static builtins::PyModuleDef]) -> Self {
|
||||
self.module_defs.extend_from_slice(defs);
|
||||
self
|
||||
@@ -254,6 +258,7 @@ impl InterpreterBuilder {
|
||||
/// Build the interpreter.
|
||||
///
|
||||
/// This consumes the configuration and returns a fully initialized Interpreter.
|
||||
#[must_use]
|
||||
pub fn build(self) -> Interpreter {
|
||||
let (vm, global_state) = initialize_main_vm(
|
||||
self.settings,
|
||||
@@ -267,6 +272,7 @@ impl InterpreterBuilder {
|
||||
}
|
||||
|
||||
/// Alias for `build()` for compatibility with the `interpreter()` pattern.
|
||||
#[must_use]
|
||||
pub fn interpreter(self) -> Interpreter {
|
||||
self.build()
|
||||
}
|
||||
@@ -312,6 +318,7 @@ impl Interpreter {
|
||||
/// // In practice, add stdlib: builder.add_native_modules(&stdlib_module_defs(&builder.ctx))
|
||||
/// let interp = builder.build();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn builder(settings: Settings) -> InterpreterBuilder {
|
||||
InterpreterBuilder::new().settings(settings)
|
||||
}
|
||||
@@ -320,6 +327,7 @@ impl Interpreter {
|
||||
/// To create an interpreter with the standard library with the `rustpython` crate, use `rustpython::InterpreterBuilder`.
|
||||
/// To create an interpreter without the `rustpython` crate, but only with `rustpython-vm`,
|
||||
/// try to build one from the source code of `InterpreterBuilder`. It will not be a one-liner but it also will not be too hard.
|
||||
#[must_use]
|
||||
pub fn without_stdlib(settings: Settings) -> Self {
|
||||
Self::with_init(settings, |_| {})
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ pub struct FramePtr(NonNull<Py<Frame>>);
|
||||
impl FramePtr {
|
||||
/// # Safety
|
||||
/// The pointed-to frame must still be alive.
|
||||
#[must_use]
|
||||
pub unsafe fn as_ref(&self) -> &Py<Frame> {
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
@@ -201,6 +202,7 @@ impl Default for StopTheWorldState {
|
||||
|
||||
#[cfg(all(unix, feature = "threading"))]
|
||||
impl StopTheWorldState {
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
requested: AtomicBool::new(false),
|
||||
@@ -2273,6 +2275,7 @@ impl AsRef<Context> for VirtualMachine {
|
||||
|
||||
/// Resolve frozen module alias to its original name.
|
||||
/// Returns the original module name if an alias exists, otherwise returns the input name.
|
||||
#[must_use]
|
||||
pub fn resolve_frozen_alias(name: &str) -> &str {
|
||||
match name {
|
||||
"_frozen_importlib" => "importlib._bootstrap",
|
||||
|
||||
@@ -31,6 +31,7 @@ pub struct PyConfig {
|
||||
}
|
||||
|
||||
impl PyConfig {
|
||||
#[must_use]
|
||||
pub fn new(settings: Settings, paths: Paths) -> Self {
|
||||
Self { settings, paths }
|
||||
}
|
||||
@@ -171,6 +172,7 @@ pub enum CheckHashPycsMode {
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
#[must_use]
|
||||
pub fn with_path(mut self, path: String) -> Self {
|
||||
self.path_list.push(path);
|
||||
self
|
||||
|
||||
@@ -345,6 +345,7 @@ fn do_suspend(stw: &super::StopTheWorldState) {
|
||||
|
||||
#[cfg(all(unix, feature = "threading"))]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn stop_requested_for_current_thread() -> bool {
|
||||
CURRENT_THREAD_SLOT.with(|slot| {
|
||||
slot.borrow()
|
||||
@@ -393,6 +394,7 @@ pub fn set_current_frame(frame: *const Frame) -> *const Frame {
|
||||
|
||||
/// Get the current thread's top frame pointer.
|
||||
/// Used by faulthandler's signal handler to start traceback walking.
|
||||
#[must_use]
|
||||
pub fn get_current_frame() -> *const Frame {
|
||||
CURRENT_FRAME.with(|c| c.load(Ordering::Relaxed) as *const Frame)
|
||||
}
|
||||
|
||||
@@ -254,6 +254,7 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn syntax_err(err: CompileError) -> SyntaxError {
|
||||
let js_err = SyntaxError::new(&format!("Error parsing Python code: {err}"));
|
||||
let _ = Reflect::set(
|
||||
|
||||
@@ -108,6 +108,7 @@ pub struct VMStore;
|
||||
|
||||
#[wasm_bindgen(js_class = vmStore)]
|
||||
impl VMStore {
|
||||
#[must_use]
|
||||
pub fn init(id: String, inject_browser_module: Option<bool>) -> WASMVirtualMachine {
|
||||
STORED_VMS.with_borrow_mut(|vms| {
|
||||
if !vms.contains_key(&id) {
|
||||
@@ -123,6 +124,7 @@ impl VMStore {
|
||||
STORED_VMS.with_borrow(|vms| vms.contains_key(&id).then_some(WASMVirtualMachine { id }))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get(id: String) -> JsValue {
|
||||
match Self::_get(id) {
|
||||
Some(wasm_vm) => wasm_vm.into(),
|
||||
@@ -142,6 +144,7 @@ impl VMStore {
|
||||
});
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn ids() -> Vec<JsValue> {
|
||||
STORED_VMS.with_borrow(|vms| vms.keys().map(|k| k.into()).collect())
|
||||
}
|
||||
@@ -178,6 +181,7 @@ impl WASMVirtualMachine {
|
||||
self.with(|stored| stored.interp.enter(|vm| f(vm, stored)))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn valid(&self) -> bool {
|
||||
STORED_VMS.with_borrow(|vms| vms.contains_key(&self.id))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user