/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn cause(&self) -> Option<&Error> { None }
+ fn cause(&self) -> Option<&dyn Error> { None }
/// Get the `TypeId` of `self`
#[doc(hidden)]
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
- fn from(err: E) -> Box<Error + 'a> {
+impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
+ fn from(err: E) -> Box<dyn Error + 'a> {
Box::new(err)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<Error + Send + Sync + 'a> {
- fn from(err: E) -> Box<Error + Send + Sync + 'a> {
+impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
+ fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
Box::new(err)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl From<String> for Box<Error + Send + Sync> {
- fn from(err: String) -> Box<Error + Send + Sync> {
+impl From<String> for Box<dyn Error + Send + Sync> {
+ fn from(err: String) -> Box<dyn Error + Send + Sync> {
#[derive(Debug)]
struct StringError(String);
}
#[stable(feature = "string_box_error", since = "1.6.0")]
-impl From<String> for Box<Error> {
- fn from(str_err: String) -> Box<Error> {
- let err1: Box<Error + Send + Sync> = From::from(str_err);
- let err2: Box<Error> = err1;
+impl From<String> for Box<dyn Error> {
+ fn from(str_err: String) -> Box<dyn Error> {
+ let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
+ let err2: Box<dyn Error> = err1;
err2
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
- fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
+impl<'a, 'b> From<&'b str> for Box<dyn Error + Send + Sync + 'a> {
+ fn from(err: &'b str) -> Box<dyn Error + Send + Sync + 'a> {
From::from(String::from(err))
}
}
#[stable(feature = "string_box_error", since = "1.6.0")]
-impl<'a> From<&'a str> for Box<Error> {
- fn from(err: &'a str) -> Box<Error> {
+impl<'a> From<&'a str> for Box<dyn Error> {
+ fn from(err: &'a str) -> Box<dyn Error> {
From::from(String::from(err))
}
}
#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a, 'b> From<Cow<'b, str>> for Box<Error + Send + Sync + 'a> {
- fn from(err: Cow<'b, str>) -> Box<Error + Send + Sync + 'a> {
+impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
+ fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
From::from(String::from(err))
}
}
#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a> From<Cow<'a, str>> for Box<Error> {
- fn from(err: Cow<'a, str>) -> Box<Error> {
+impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
+ fn from(err: Cow<'a, str>) -> Box<dyn Error> {
From::from(String::from(err))
}
}
Error::description(&**self)
}
- fn cause(&self) -> Option<&Error> {
+ fn cause(&self) -> Option<&dyn Error> {
Error::cause(&**self)
}
}
}
// copied from any.rs
-impl Error + 'static {
+impl dyn Error + 'static {
/// Returns true if the boxed type is the same as `T`
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe {
- Some(&*(self as *const Error as *const T))
+ Some(&*(self as *const dyn Error as *const T))
}
} else {
None
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe {
- Some(&mut *(self as *mut Error as *mut T))
+ Some(&mut *(self as *mut dyn Error as *mut T))
}
} else {
None
}
}
-impl Error + 'static + Send {
+impl dyn Error + 'static + Send {
/// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
- <Error + 'static>::is::<T>(self)
+ <dyn Error + 'static>::is::<T>(self)
}
/// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
- <Error + 'static>::downcast_ref::<T>(self)
+ <dyn Error + 'static>::downcast_ref::<T>(self)
}
/// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
- <Error + 'static>::downcast_mut::<T>(self)
+ <dyn Error + 'static>::downcast_mut::<T>(self)
}
}
-impl Error + 'static + Send + Sync {
+impl dyn Error + 'static + Send + Sync {
/// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
- <Error + 'static>::is::<T>(self)
+ <dyn Error + 'static>::is::<T>(self)
}
/// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
- <Error + 'static>::downcast_ref::<T>(self)
+ <dyn Error + 'static>::downcast_ref::<T>(self)
}
/// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
- <Error + 'static>::downcast_mut::<T>(self)
+ <dyn Error + 'static>::downcast_mut::<T>(self)
}
}
-impl Error {
+impl dyn Error {
#[inline]
#[stable(feature = "error_downcast", since = "1.3.0")]
/// Attempt to downcast the box to a concrete type.
- pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
if self.is::<T>() {
unsafe {
- let raw: *mut Error = Box::into_raw(self);
+ let raw: *mut dyn Error = Box::into_raw(self);
Ok(Box::from_raw(raw as *mut T))
}
} else {
}
}
-impl Error + Send {
+impl dyn Error + Send {
#[inline]
#[stable(feature = "error_downcast", since = "1.3.0")]
/// Attempt to downcast the box to a concrete type.
pub fn downcast<T: Error + 'static>(self: Box<Self>)
- -> Result<Box<T>, Box<Error + Send>> {
- let err: Box<Error> = self;
- <Error>::downcast(err).map_err(|s| unsafe {
+ -> Result<Box<T>, Box<dyn Error + Send>> {
+ let err: Box<dyn Error> = self;
+ <dyn Error>::downcast(err).map_err(|s| unsafe {
// reapply the Send marker
- transmute::<Box<Error>, Box<Error + Send>>(s)
+ transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
})
}
}
-impl Error + Send + Sync {
+impl dyn Error + Send + Sync {
#[inline]
#[stable(feature = "error_downcast", since = "1.3.0")]
/// Attempt to downcast the box to a concrete type.
pub fn downcast<T: Error + 'static>(self: Box<Self>)
-> Result<Box<T>, Box<Self>> {
- let err: Box<Error> = self;
- <Error>::downcast(err).map_err(|s| unsafe {
+ let err: Box<dyn Error> = self;
+ <dyn Error>::downcast(err).map_err(|s| unsafe {
// reapply the Send+Sync marker
- transmute::<Box<Error>, Box<Error + Send + Sync>>(s)
+ transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
})
}
}
"C string contained non-utf8 bytes"
}
- fn cause(&self) -> Option<&Error> {
+ fn cause(&self) -> Option<&dyn Error> {
Some(&self.error)
}
}
#[derive(Debug)]
struct Custom {
kind: ErrorKind,
- error: Box<error::Error+Send+Sync>,
+ error: Box<dyn error::Error+Send+Sync>,
}
/// A list specifying general categories of I/O error.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<E>(kind: ErrorKind, error: E) -> Error
- where E: Into<Box<error::Error+Send+Sync>>
+ where E: Into<Box<dyn error::Error+Send+Sync>>
{
Self::_new(kind, error.into())
}
- fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
+ fn _new(kind: ErrorKind, error: Box<dyn error::Error+Send+Sync>) -> Error {
Error {
repr: Repr::Custom(Box::new(Custom {
kind,
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
- pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
+ pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
- pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
+ pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
- pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
+ pub fn into_inner(self) -> Option<Box<dyn error::Error+Send+Sync>> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
}
}
- fn cause(&self) -> Option<&error::Error> {
+ fn cause(&self) -> Option<&dyn error::Error> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
}
}
-fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
+fn read_one_byte(reader: &mut dyn Read) -> Option<Result<u8>> {
let mut buf = [0];
loop {
return match reader.read(&mut buf) {
CharsError::Other(ref e) => std_error::Error::description(e),
}
}
- fn cause(&self) -> Option<&std_error::Error> {
+ fn cause(&self) -> Option<&dyn std_error::Error> {
match *self {
CharsError::NotUtf8 => None,
CharsError::Other(ref e) => e.cause(),
/// Stdout used by print! and println! macros
thread_local! {
- static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = {
+ static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
RefCell::new(None)
}
}
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
-pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
+pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
use panicking::LOCAL_STDERR;
use mem;
LOCAL_STDERR.with(move |slot| {
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
-pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
+pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
use mem;
LOCAL_STDOUT.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), sink)
/// However, if the actual I/O causes an error, this function does panic.
fn print_to<T>(
args: fmt::Arguments,
- local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
+ local_s: &'static LocalKey<RefCell<Option<Box<dyn Write+Send>>>>,
global_s: fn() -> T,
label: &str,
)
// Don't link to std. We are std.
#![no_std]
+#![deny(bare_trait_objects)]
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
}
// Return result of first successful parser
- fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T> + 'static>])
+ fn read_or<T>(&mut self, parsers: &mut [Box<dyn FnMut(&mut Parser) -> Option<T> + 'static>])
-> Option<T> {
for pf in parsers {
if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) {
/// }
/// ```
#[stable(feature = "resume_unwind", since = "1.9.0")]
-pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
+pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
panicking::update_count_then_panic(payload)
}
use thread;
thread_local! {
- pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
+ pub static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
RefCell::new(None)
}
}
#[derive(Copy, Clone)]
enum Hook {
Default,
- Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)),
+ Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)),
}
static HOOK_LOCK: RWLock = RWLock::new();
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
-pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) {
+pub fn set_hook(hook: Box<dyn Fn(&PanicInfo) + 'static + Sync + Send>) {
if thread::panicking() {
panic!("cannot modify the panic hook from a panicking thread");
}
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
-pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
+pub fn take_hook() -> Box<dyn Fn(&PanicInfo) + 'static + Sync + Send> {
if thread::panicking() {
panic!("cannot modify the panic hook from a panicking thread");
}
let thread = thread_info::current_thread();
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
- let write = |err: &mut ::io::Write| {
+ let write = |err: &mut dyn (::io::Write)| {
let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
name, msg, location);
pub use realstd::rt::update_panic_count;
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
-pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
+pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
#[allow(unions_with_drop_fields)]
union Data<F, R> {
f: F,
}
unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
- fn box_me_up(&mut self) -> *mut (Any + Send) {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
let contents = mem::replace(self.fill(), String::new());
Box::into_raw(Box::new(contents))
}
- fn get(&mut self) -> &(Any + Send) {
+ fn get(&mut self) -> &(dyn Any + Send) {
self.fill()
}
}
}
unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
- fn box_me_up(&mut self) -> *mut (Any + Send) {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
let data = match self.inner.take() {
- Some(a) => Box::new(a) as Box<Any + Send>,
+ Some(a) => Box::new(a) as Box<dyn Any + Send>,
None => Box::new(()),
};
Box::into_raw(data)
}
- fn get(&mut self) -> &(Any + Send) {
+ fn get(&mut self) -> &(dyn Any + Send) {
match self.inner {
Some(ref a) => a,
None => &(),
/// Executes the primary logic for a panic, including checking for recursive
/// panics, panic hooks, and finally dispatching to the panic runtime to either
/// abort or unwind.
-fn rust_panic_with_hook(payload: &mut BoxMeUp,
+fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
message: Option<&fmt::Arguments>,
file_line_col: &(&str, u32, u32)) -> ! {
let (file, line, col) = *file_line_col;
}
/// Shim around rust_panic. Called by resume_unwind.
-pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! {
+pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
update_panic_count(1);
- struct RewrapBox(Box<Any + Send>);
+ struct RewrapBox(Box<dyn Any + Send>);
unsafe impl BoxMeUp for RewrapBox {
- fn box_me_up(&mut self) -> *mut (Any + Send) {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
Box::into_raw(mem::replace(&mut self.0, Box::new(())))
}
- fn get(&mut self) -> &(Any + Send) {
+ fn get(&mut self) -> &(dyn Any + Send) {
&*self.0
}
}
/// A private no-mangle function on which to slap yer breakpoints.
#[no_mangle]
#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
-pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! {
+pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
let code = unsafe {
- let obj = &mut msg as *mut &mut BoxMeUp;
+ let obj = &mut msg as *mut &mut dyn BoxMeUp;
__rust_start_panic(obj as usize)
};
rtabort!("failed to initiate panic, error {}", code)
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let stdout_utf8 = str::from_utf8(&self.stdout);
- let stdout_debug: &fmt::Debug = match stdout_utf8 {
+ let stdout_debug: &dyn fmt::Debug = match stdout_utf8 {
Ok(ref str) => str,
Err(_) => &self.stdout
};
let stderr_utf8 = str::from_utf8(&self.stderr);
- let stderr_debug: &fmt::Debug = match stderr_utf8 {
+ let stderr_debug: &dyn fmt::Debug = match stderr_utf8 {
Ok(ref str) => str,
Err(_) => &self.stderr
};
// To reduce the generated code of the new `lang_start`, this function is doing
// the real work.
#[cfg(not(test))]
-fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe),
+fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + ::panic::RefUnwindSafe),
argc: isize, argv: *const *const u8) -> isize {
use panic;
use sys;
"sending on a closed channel"
}
- fn cause(&self) -> Option<&error::Error> {
+ fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
}
}
- fn cause(&self) -> Option<&error::Error> {
+ fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
"receiving on a closed channel"
}
- fn cause(&self) -> Option<&error::Error> {
+ fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
}
}
- fn cause(&self) -> Option<&error::Error> {
+ fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
}
}
- fn cause(&self) -> Option<&error::Error> {
+ fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
next: *mut Handle<'static, ()>,
prev: *mut Handle<'static, ()>,
added: bool,
- packet: &'rx (Packet+'rx),
+ packet: &'rx (dyn Packet+'rx),
// due to our fun transmutes, we be sure to place this at the end. (nothing
// previous relies on T)
#[cold]
fn call_inner(&'static self,
ignore_poisoning: bool,
- init: &mut FnMut(bool)) {
+ init: &mut dyn FnMut(bool)) {
let mut state = self.state.load(Ordering::SeqCst);
'outer: loop {
}
impl Thread {
- pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
+ pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>)
-> io::Result<Thread> {
let p = box p;
use mem;
use sys_common::mutex::Mutex;
-type Queue = Vec<Box<FnBox()>>;
+type Queue = Vec<Box<dyn FnBox()>>;
// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
}
}
-pub fn push(f: Box<FnBox()>) -> bool {
+pub fn push(f: Box<dyn FnBox()>) -> bool {
unsafe {
let _guard = LOCK.lock();
if init() {
const MAX_NB_FRAMES: usize = 100;
/// Prints the current backtrace.
-pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
static LOCK: Mutex = Mutex::new();
// Use a lock to prevent mixed output in multithreading context.
}
}
-fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
let mut frames = [Frame {
exact_position: ptr::null(),
symbol_addr: ptr::null(),
///
/// These output functions should now be used everywhere to ensure consistency.
/// You may want to also use `output_fileline`.
-fn output(w: &mut Write, idx: usize, frame: Frame,
+fn output(w: &mut dyn Write, idx: usize, frame: Frame,
s: Option<&str>, format: PrintFormat) -> io::Result<()> {
// Remove the `17: 0x0 - <unknown>` line.
if format == PrintFormat::Short && frame.exact_position == ptr::null() {
///
/// See also `output`.
#[allow(dead_code)]
-fn output_fileline(w: &mut Write,
+fn output_fileline(w: &mut dyn Write,
file: &[u8],
line: u32,
format: PrintFormat) -> io::Result<()> {
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
-pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Result<()> {
+pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> {
// During ThinLTO LLVM may import and rename internal symbols, so strip out
// those endings first as they're one of the last manglings applied to
// symbol names.
}
}
- fn cause(&self) -> Option<&Error> {
+ fn cause(&self) -> Option<&dyn Error> {
match *self {
TryLockError::Poisoned(ref p) => Some(p),
_ => None
let _handler = stack_overflow::Handler::new();
// Finally, let's run some code.
- Box::from_raw(main as *mut Box<FnBox()>)()
+ Box::from_raw(main as *mut Box<dyn FnBox()>)()
}
pub fn min_stack() -> usize {
///
/// [`Result`]: ../../std/result/enum.Result.html
#[stable(feature = "rust1", since = "1.0.0")]
-pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>;
+pub type Result<T> = ::result::Result<T, Box<dyn Any + Send + 'static>>;
// This packet is used to communicate the return value between the child thread
// and the parent thread. Memory is shared through the `Arc` within and there's