method_chaining 0.1.0

A Rust procedural macro that automatically makes functions and structs chainable.
Documentation
use method_chaining::chainable;

#[test]
fn test_chainable_basic() {
    struct Builder {
        value: i32,
    }

    impl Builder {
        fn new() -> Self {
            Self { value: 0 }
        }

        #[chainable]
        fn set_value(&mut self, val: i32) {
            self.value = val;
        }

        #[chainable]
        fn add(&mut self, val: i32) {
            self.value += val;
        }

        fn build(&self) -> i32 {
            self.value
        }
    }

    let result = Builder::new().set_value(10).add(5).add(3).build();

    assert_eq!(result, 18);
}

#[test]
fn test_chainable_mutiple_returns() {
    struct Counter {
        max: i32,
        count: i32,
    }

    impl Counter {
        fn new() -> Self {
            Self { max: 10, count: 0 }
        }

        #[chainable]
        fn increment(&mut self) {
            if self.count >= self.max {
                return;
            }
            self.count += 1;
            return;
        }

        fn get_count(&self) -> i32 {
            self.count
        }
    }

    let result = Counter::new().increment().increment().get_count();

    assert_eq!(result, 2);
}

#[test]
fn test_chainable_string_builder() {
    struct StringBuilder {
        content: String,
    }

    impl StringBuilder {
        fn new() -> Self {
            Self {
                content: String::new(),
            }
        }

        #[chainable]
        fn append(&mut self, s: &str) {
            self.content.push_str(s);
        }

        #[chainable]
        fn append_char(&mut self, c: char) {
            self.content.push(c);
        }

        fn finish(&self) -> String {
            self.content.clone()
        }
    }

    let result = StringBuilder::new()
        .append("Hello")
        .append_char(' ')
        .append("World")
        .append_char('!')
        .finish();

    assert_eq!(result, "Hello World!");
}

#[test]
fn test_chainable_config() {
    #[derive(Debug, PartialEq, Clone)]
    struct Config {
        host: String,
        port: u16,
        timeout: u64,
        debug: bool,
    }

    impl Config {
        fn new() -> Self {
            Self {
                host: "localhost".to_string(),
                port: 8080,
                timeout: 30,
                debug: false,
            }
        }

        #[chainable]
        fn with_host(&mut self, host: &str) {
            self.host = host.to_string();
        }

        #[chainable]
        fn with_port(&mut self, port: u16) {
            self.port = port;
        }

        #[chainable]
        fn with_timeout(&mut self, timeout: u64) {
            self.timeout = timeout;
        }

        #[chainable]
        fn enable_debug(&mut self) {
            self.debug = true;
        }
    }

    let config = Config::new()
        .with_host("example.com")
        .with_port(9000)
        .with_timeout(60)
        .enable_debug()
        .clone();

    let expected = Config {
        host: "example.com".to_string(),
        port: 9000,
        timeout: 60,
        debug: true,
    };

    assert_eq!(config, expected);
}

#[test]
fn test_chainable_struct() {
    #[derive(Debug, PartialEq)]
    #[chainable]
    struct Config {
        host: String,
        port: u16,
        timeout: u32,
    }

    impl Config {
        fn new() -> Self {
            Self {
                host: "localhost".to_string(),
                port: 8080,
                timeout: 30,
            }
        }
    }

    let expected = Config {
        host: "example.com".to_string(),
        port: 9000,
        timeout: 60,
    };

    // 测试链式调用
    let config = Config::new()
        .with_host("example.com".to_string())
        .with_port(9000)
        .with_timeout(60);

    assert_eq!(config, expected);
}

// #[test]
// fn error_return_type() {
//     let t = trybuild::TestCases::new();
//     t.compile_fail("tests/ui/return_type.rs");
// }