trait MyAdd {
    type Output;
    fn my_add(self, other: Self) -> Self::Output;
}

impl MyAdd for i32 {
    type Output = i32;
    fn my_add(self, other: Self) -> Self::Output {
        self + other
    }
}

trait MyAddGeneric<T> {
    fn my_add_generic(self, other: Self) -> T;
}

impl MyAddGeneric<i32> for i32 {
    fn my_add_generic(self, other: i32) -> i32 {
        self + other
    }
}

struct MyString(String);

trait GetRef {
    type Output: ?Sized;
    fn get_ref(&self) -> &Self::Output;
}

impl GetRef for MyString {
    type Output = str;
    fn get_ref(&self) -> &Self::Output {
        self.0.as_str()
    }
}

trait GetRefGeneric<T: ?Sized> {
    fn get_ref_generic(&self) -> &T;
}

impl GetRefGeneric<str> for MyString {
    fn get_ref_generic(&self) -> &str {
        self.0.as_str()
    }
}

fn main() {
    let my_string = MyString("Hello, world!".to_string());
    println!("String: {}", my_string.get_ref());
    println!("String: {}", my_string.get_ref_generic());
    let a = 5;
    let b = 10;
    println!("{a} + {b} = {}", a.my_add(b));
    println!("{a} + {b} = {}", a.my_add_generic(b));
}
