1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
//! [![crates.io](https://meritbadge.herokuapp.com/turbonone)](https://crates.io/crates/turbonone)
//! [![docs.rs](https://docs.rs/turbonone/badge.svg)](https://docs.rs/turbonone/)
//! [![license](https://img.shields.io/crates/l/turbonone)](https://github.com/WilliamVenner/turbonone/blob/master/LICENSE)
//!
//! Simple macro for calling functions with generic `Option<T>` arguments.
//!
//! ## Usage
//!
//! Add to your [Cargo.toml](https://doc.rust-lang.org/cargo/reference/manifest.html) file:
//!
//! ```toml
//! [dependencies]
//! turbonone = "0.*"
//! ```
//!
//! ## The Problem
//!
//! ```ignore
//! # extern crate core;
//! # extern crate turbonone;
//! # use turbonone::turbonone;
//! fn my_function<T>(arg: Option<T>) -> &'static str {
//!     "Works!"
//! }
//!
//! fn my_box_function<T>(arg: Option<Box<T>>) -> &'static str {
//!     "Works!"
//! }
//!
//! fn my_complex_function<T>(arg: Option<Arc<Box<T>>>) -> &'static str {
//!     "Works!"
//! }
//!
//! my_function(None); // cannot infer type for type parameter `T` declared on the associated function `my_function`
//! my_function(Some("An argument")); // Works!
//!
//! my_box_function(None); // cannot infer type for type parameter `T` declared on the associated function `my_box_function`
//! my_box_function(Some(Box::new("An argument"))); // Works!
//!
//! my_complex_function(None); // cannot infer type for type parameter `T` declared on the associated function `my_complex_function`
//! my_complex_function(Some(Arc::new(Box::new("An argument")))); // Works!
//! ```
//!
//! ## The Solution
//!
//! ```rust
//! # extern crate core;
//! #[macro_use] extern crate turbonone;
//! # use std::sync::Arc;
//!
//! fn my_function<T>(arg: Option<T>) -> &'static str {
//!     "Works!"
//! }
//!
//! fn my_box_function<T>(arg: Option<Box<T>>) -> &'static str {
//!     "Works!"
//! }
//!
//! fn my_complex_function<T>(arg: Option<Arc<Box<T>>>) -> &'static str {
//!     "Works!"
//! }
//!
//! my_function(turbonone!()); // Works!
//! my_function(Some("An argument")); // Works!
//!
//! my_box_function(turbonone!(Box)); // Works!
//! my_box_function(turbonone!(Box<()>)); // Works!
//! my_box_function(Some(Box::new("An argument"))); // Works!
//!
//! my_complex_function(turbonone!(Arc<Box<()>>)); // Works!
//! my_complex_function(Some(Arc::new(Box::new("An argument")))); // Works!
//! ```

#![no_std]

extern crate alloc;
use alloc::{format, string::ToString};

extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro]
pub fn turbonone(tokens: TokenStream) -> TokenStream {
    if tokens.is_empty() {
        "::core::option::Option::None::<()>".parse().unwrap()
    } else {
        let mut elided_unit_type = true;
        {
            let mut i: u8 = 0;
            for _ in tokens.clone().into_iter() {
                i += 1;
                if i > 1 {
                    elided_unit_type = false;
                    break;
                }
            }
        }
        if elided_unit_type {
            format!("::core::option::Option::None::<{}<()>>", tokens.to_string())
        } else {
            format!("::core::option::Option::None::<{}>", tokens.to_string())
        }
        .parse()
        .unwrap()
    }
}