mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
Auto merge of #76327 - lzutao:split-core-num, r=SimonSapin
Split `core/num/mod.rs` to smaller mods Note for reviewer: * I split to multiple commits for easier reviewing, but I could git squash them all to one if requested. * Recommend pulling this change locally and using advanced git diff viewer or this command: ``` git show --reverse --color-moved=dimmed-zebra master.. ``` --- I split `core/num/mod.rs` to these modules: * `error`: For error structs like `ParseIntError`. * blanket `shells` dir: For dummy number type modules: std::i32, std::f32, and the likes. Why? See below. * `int_macros` and `uint_macros`: Real implementation of all integer types via `int_impl` and `uint_impl` * `nonzero`: For `NonZero*` types and their implementations. * `wrapping`: For `Wrapping<T>` types.
This commit is contained in:
commit
59fb88d061
@ -169,34 +169,34 @@ mod macros;
|
||||
#[macro_use]
|
||||
mod internal_macros;
|
||||
|
||||
#[path = "num/int_macros.rs"]
|
||||
#[path = "num/shells/int_macros.rs"]
|
||||
#[macro_use]
|
||||
mod int_macros;
|
||||
|
||||
#[path = "num/i128.rs"]
|
||||
#[path = "num/shells/i128.rs"]
|
||||
pub mod i128;
|
||||
#[path = "num/i16.rs"]
|
||||
#[path = "num/shells/i16.rs"]
|
||||
pub mod i16;
|
||||
#[path = "num/i32.rs"]
|
||||
#[path = "num/shells/i32.rs"]
|
||||
pub mod i32;
|
||||
#[path = "num/i64.rs"]
|
||||
#[path = "num/shells/i64.rs"]
|
||||
pub mod i64;
|
||||
#[path = "num/i8.rs"]
|
||||
#[path = "num/shells/i8.rs"]
|
||||
pub mod i8;
|
||||
#[path = "num/isize.rs"]
|
||||
#[path = "num/shells/isize.rs"]
|
||||
pub mod isize;
|
||||
|
||||
#[path = "num/u128.rs"]
|
||||
#[path = "num/shells/u128.rs"]
|
||||
pub mod u128;
|
||||
#[path = "num/u16.rs"]
|
||||
#[path = "num/shells/u16.rs"]
|
||||
pub mod u16;
|
||||
#[path = "num/u32.rs"]
|
||||
#[path = "num/shells/u32.rs"]
|
||||
pub mod u32;
|
||||
#[path = "num/u64.rs"]
|
||||
#[path = "num/shells/u64.rs"]
|
||||
pub mod u64;
|
||||
#[path = "num/u8.rs"]
|
||||
#[path = "num/shells/u8.rs"]
|
||||
pub mod u8;
|
||||
#[path = "num/usize.rs"]
|
||||
#[path = "num/shells/usize.rs"]
|
||||
pub mod usize;
|
||||
|
||||
#[path = "num/f32.rs"]
|
||||
|
151
library/core/src/num/error.rs
Normal file
151
library/core/src/num/error.rs
Normal file
@ -0,0 +1,151 @@
|
||||
//! Error types for conversion to integral types.
|
||||
|
||||
use crate::convert::Infallible;
|
||||
use crate::fmt;
|
||||
|
||||
/// The error type returned when a checked integral type conversion fails.
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct TryFromIntError(pub(crate) ());
|
||||
|
||||
impl TryFromIntError {
|
||||
#[unstable(
|
||||
feature = "int_error_internals",
|
||||
reason = "available through Error trait and this method should \
|
||||
not be exposed publicly",
|
||||
issue = "none"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub fn __description(&self) -> &str {
|
||||
"out of range integral type conversion attempted"
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
impl fmt::Display for TryFromIntError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.__description().fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
impl From<Infallible> for TryFromIntError {
|
||||
fn from(x: Infallible) -> TryFromIntError {
|
||||
match x {}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
impl From<!> for TryFromIntError {
|
||||
fn from(never: !) -> TryFromIntError {
|
||||
// Match rather than coerce to make sure that code like
|
||||
// `From<Infallible> for TryFromIntError` above will keep working
|
||||
// when `Infallible` becomes an alias to `!`.
|
||||
match never {}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error which can be returned when parsing an integer.
|
||||
///
|
||||
/// This error is used as the error type for the `from_str_radix()` functions
|
||||
/// on the primitive integer types, such as [`i8::from_str_radix`].
|
||||
///
|
||||
/// # Potential causes
|
||||
///
|
||||
/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
|
||||
/// in the string e.g., when it is obtained from the standard input.
|
||||
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
|
||||
///
|
||||
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
|
||||
/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// if let Err(e) = i32::from_str_radix("a12", 10) {
|
||||
/// println!("Failed conversion to i32: {}", e);
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct ParseIntError {
|
||||
pub(super) kind: IntErrorKind,
|
||||
}
|
||||
|
||||
/// Enum to store the various types of errors that can cause parsing an integer to fail.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_error_matching)]
|
||||
///
|
||||
/// # fn main() {
|
||||
/// if let Err(e) = i32::from_str_radix("a12", 10) {
|
||||
/// println!("Failed conversion to i32: {:?}", e.kind());
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(
|
||||
feature = "int_error_matching",
|
||||
reason = "it can be useful to match errors when making error messages \
|
||||
for integer parsing",
|
||||
issue = "22639"
|
||||
)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum IntErrorKind {
|
||||
/// Value being parsed is empty.
|
||||
///
|
||||
/// Among other causes, this variant will be constructed when parsing an empty string.
|
||||
Empty,
|
||||
/// Contains an invalid digit.
|
||||
///
|
||||
/// Among other causes, this variant will be constructed when parsing a string that
|
||||
/// contains a letter.
|
||||
InvalidDigit,
|
||||
/// Integer is too large to store in target integer type.
|
||||
Overflow,
|
||||
/// Integer is too small to store in target integer type.
|
||||
Underflow,
|
||||
/// Value was Zero
|
||||
///
|
||||
/// This variant will be emitted when the parsing string has a value of zero, which
|
||||
/// would be illegal for non-zero types.
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl ParseIntError {
|
||||
/// Outputs the detailed cause of parsing an integer failing.
|
||||
#[unstable(
|
||||
feature = "int_error_matching",
|
||||
reason = "it can be useful to match errors when making error messages \
|
||||
for integer parsing",
|
||||
issue = "22639"
|
||||
)]
|
||||
pub fn kind(&self) -> &IntErrorKind {
|
||||
&self.kind
|
||||
}
|
||||
#[unstable(
|
||||
feature = "int_error_internals",
|
||||
reason = "available through Error trait and this method should \
|
||||
not be exposed publicly",
|
||||
issue = "none"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub fn __description(&self) -> &str {
|
||||
match self.kind {
|
||||
IntErrorKind::Empty => "cannot parse integer from empty string",
|
||||
IntErrorKind::InvalidDigit => "invalid digit found in string",
|
||||
IntErrorKind::Overflow => "number too large to fit in target type",
|
||||
IntErrorKind::Underflow => "number too small to fit in target type",
|
||||
IntErrorKind::Zero => "number would be zero for non-zero type",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for ParseIntError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.__description().fmt(f)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
190
library/core/src/num/nonzero.rs
Normal file
190
library/core/src/num/nonzero.rs
Normal file
@ -0,0 +1,190 @@
|
||||
//! Definitions of integer that is known not to equal zero.
|
||||
|
||||
use crate::fmt;
|
||||
use crate::ops::{BitOr, BitOrAssign};
|
||||
use crate::str::FromStr;
|
||||
|
||||
use super::from_str_radix;
|
||||
use super::{IntErrorKind, ParseIntError};
|
||||
|
||||
macro_rules! doc_comment {
|
||||
($x:expr, $($tt:tt)*) => {
|
||||
#[doc = $x]
|
||||
$($tt)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_nonzero_fmt {
|
||||
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
|
||||
$(
|
||||
#[$stability]
|
||||
impl fmt::$Trait for $Ty {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.get().fmt(f)
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! nonzero_integers {
|
||||
( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
|
||||
$(
|
||||
doc_comment! {
|
||||
concat!("An integer that is known not to equal zero.
|
||||
|
||||
This enables some memory layout optimization.
|
||||
For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:
|
||||
|
||||
```rust
|
||||
use std::mem::size_of;
|
||||
assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
|
||||
">());
|
||||
```"),
|
||||
#[$stability]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(1)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
pub struct $Ty($Int);
|
||||
}
|
||||
|
||||
impl $Ty {
|
||||
/// Creates a non-zero without checking the value.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The value must not be zero.
|
||||
#[$stability]
|
||||
#[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
|
||||
#[inline]
|
||||
pub const unsafe fn new_unchecked(n: $Int) -> Self {
|
||||
// SAFETY: this is guaranteed to be safe by the caller.
|
||||
unsafe { Self(n) }
|
||||
}
|
||||
|
||||
/// Creates a non-zero if the given value is not zero.
|
||||
#[$stability]
|
||||
#[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
|
||||
#[inline]
|
||||
pub const fn new(n: $Int) -> Option<Self> {
|
||||
if n != 0 {
|
||||
// SAFETY: we just checked that there's no `0`
|
||||
Some(unsafe { Self(n) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value as a primitive type.
|
||||
#[$stability]
|
||||
#[inline]
|
||||
#[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
|
||||
pub const fn get(self) -> $Int {
|
||||
self.0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[stable(feature = "from_nonzero", since = "1.31.0")]
|
||||
impl From<$Ty> for $Int {
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
|
||||
fn from(nonzero: $Ty) -> Self {
|
||||
nonzero.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
|
||||
impl BitOr for $Ty {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
// SAFETY: since `self` and `rhs` are both nonzero, the
|
||||
// result of the bitwise-or will be nonzero.
|
||||
unsafe { $Ty::new_unchecked(self.get() | rhs.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
|
||||
impl BitOr<$Int> for $Ty {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn bitor(self, rhs: $Int) -> Self::Output {
|
||||
// SAFETY: since `self` is nonzero, the result of the
|
||||
// bitwise-or will be nonzero regardless of the value of
|
||||
// `rhs`.
|
||||
unsafe { $Ty::new_unchecked(self.get() | rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
|
||||
impl BitOr<$Ty> for $Int {
|
||||
type Output = $Ty;
|
||||
#[inline]
|
||||
fn bitor(self, rhs: $Ty) -> Self::Output {
|
||||
// SAFETY: since `rhs` is nonzero, the result of the
|
||||
// bitwise-or will be nonzero regardless of the value of
|
||||
// `self`.
|
||||
unsafe { $Ty::new_unchecked(self | rhs.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
|
||||
impl BitOrAssign for $Ty {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = *self | rhs;
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
|
||||
impl BitOrAssign<$Int> for $Ty {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: $Int) {
|
||||
*self = *self | rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl_nonzero_fmt! {
|
||||
#[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
nonzero_integers! {
|
||||
#[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8);
|
||||
#[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16);
|
||||
#[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32);
|
||||
#[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64);
|
||||
#[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128);
|
||||
#[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize);
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8);
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16);
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32);
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64);
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128);
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
|
||||
}
|
||||
|
||||
macro_rules! from_str_radix_nzint_impl {
|
||||
($($t:ty)*) => {$(
|
||||
#[stable(feature = "nonzero_parse", since = "1.35.0")]
|
||||
impl FromStr for $t {
|
||||
type Err = ParseIntError;
|
||||
fn from_str(src: &str) -> Result<Self, Self::Err> {
|
||||
Self::new(from_str_radix(src, 10)?)
|
||||
.ok_or(ParseIntError {
|
||||
kind: IntErrorKind::Zero
|
||||
})
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
|
||||
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
|
49
library/core/src/num/shells/int_macros.rs
Normal file
49
library/core/src/num/shells/int_macros.rs
Normal file
@ -0,0 +1,49 @@
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! doc_comment {
|
||||
($x:expr, $($tt:tt)*) => {
|
||||
#[doc = $x]
|
||||
$($tt)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! int_module {
|
||||
($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
|
||||
($T:ident, #[$attr:meta]) => (
|
||||
doc_comment! {
|
||||
concat!("The smallest value that can be represented by this integer type.
|
||||
Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead.
|
||||
|
||||
# Examples
|
||||
|
||||
```rust
|
||||
// deprecated way
|
||||
let min = std::", stringify!($T), "::MIN;
|
||||
|
||||
// intended way
|
||||
let min = ", stringify!($T), "::MIN;
|
||||
```
|
||||
"),
|
||||
#[$attr]
|
||||
pub const MIN: $T = $T::MIN;
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("The largest value that can be represented by this integer type.
|
||||
Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead.
|
||||
|
||||
# Examples
|
||||
|
||||
```rust
|
||||
// deprecated way
|
||||
let max = std::", stringify!($T), "::MAX;
|
||||
|
||||
// intended way
|
||||
let max = ", stringify!($T), "::MAX;
|
||||
```
|
||||
"),
|
||||
#[$attr]
|
||||
pub const MAX: $T = $T::MAX;
|
||||
}
|
||||
)
|
||||
}
|
1955
library/core/src/num/uint_macros.rs
Normal file
1955
library/core/src/num/uint_macros.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,83 @@
|
||||
use super::Wrapping;
|
||||
//! Definitions of `Wrapping<T>`.
|
||||
|
||||
use crate::ops::*;
|
||||
use crate::fmt;
|
||||
use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
||||
use crate::ops::{BitXor, BitXorAssign, Div, DivAssign};
|
||||
use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign};
|
||||
use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign};
|
||||
|
||||
/// Provides intentionally-wrapped arithmetic on `T`.
|
||||
///
|
||||
/// Operations like `+` on `u32` values are intended to never overflow,
|
||||
/// and in some debug configurations overflow is detected and results
|
||||
/// in a panic. While most arithmetic falls into this category, some
|
||||
/// code explicitly expects and relies upon modular arithmetic (e.g.,
|
||||
/// hashing).
|
||||
///
|
||||
/// Wrapping arithmetic can be achieved either through methods like
|
||||
/// `wrapping_add`, or through the `Wrapping<T>` type, which says that
|
||||
/// all standard arithmetic operations on the underlying value are
|
||||
/// intended to have wrapping semantics.
|
||||
///
|
||||
/// The underlying value can be retrieved through the `.0` index of the
|
||||
/// `Wrapping` tuple.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::num::Wrapping;
|
||||
///
|
||||
/// let zero = Wrapping(0u32);
|
||||
/// let one = Wrapping(1u32);
|
||||
///
|
||||
/// assert_eq!(u32::MAX, (zero - one).0);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for Wrapping<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "wrapping_display", since = "1.10.0")]
|
||||
impl<T: fmt::Display> fmt::Display for Wrapping<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "wrapping_fmt", since = "1.11.0")]
|
||||
impl<T: fmt::Binary> fmt::Binary for Wrapping<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "wrapping_fmt", since = "1.11.0")]
|
||||
impl<T: fmt::Octal> fmt::Octal for Wrapping<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "wrapping_fmt", since = "1.11.0")]
|
||||
impl<T: fmt::LowerHex> fmt::LowerHex for Wrapping<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "wrapping_fmt", since = "1.11.0")]
|
||||
impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! sh_impl_signed {
|
||||
|
Loading…
Reference in New Issue
Block a user