Как сопоставить строку с параметрами универсального типа функции? - PullRequest
0 голосов
/ 01 марта 2019

Мне нужно вызвать универсальный метод в содержимом String, который поступает от вызывающего FFI, а не из статического &str в коде:

match endpoint.as_ref() {
    "documents" => get_objs_as_json::<Document, JsonDocument>(db_url, sql),
    "theme_links" => get_objs_as_json::<ThemeLink, JsonThemeLink>(db_url, sql),
    "dressing_links" => get_objs_as_json::<DressingLink, JsonDressingLink>(db_url, sql),
    "dressing_configurations" => {
        get_objs_as_json::<DressingConfiguration, JsonDressingConfiguration>(db_url, sql)
    }
    &_ => Err(BackendError::InvalidArgument(endpoint)),
}

Это работает, нодействительно ужасно, и мне нужно делать это для каждого общего метода, который у меня есть ...

Я пытался создать хэш-карту типа endpoint => (InputStruct, OutputStruct), но я не могу хранить и использовать такие типы.

Возможно, я могу сделать это с помощью макроса, но я не знаю, как преобразовать строковый параметр в типы в макросе.

EDIT Хорошо, пытаясь переформулировать.У меня есть универсальный метод, который получает данные в моей базе данных по типу структуры, а затем преобразовывает их в какую-то другую структуру.Но мой вызывающий не знает названия структур, поэтому мне нужна оболочка для преобразования произвольной строки в пару типов.Идея здесь состоит в том, чтобы заменить (как в макросе C, даже если я знаю, что макросы Rust отличаются)

get_and_convert("documents", params)

на

get_and_convert<Document, JsonDocument>(params)

Это потому, что параметр "documents" приходитиз FFI вызывающая сторона не знает внутреннюю ржавчину и не может вызвать универсальный метод.

как в:

pub struct Document {
    pub a: i32,
}

pub struct JsonDocument {
    pub a: i32,
}

impl JsonDocument {
    pub fn to_json(&self) -> String {
        // …
    }
}

impl From<Document> for JsonDocument {
    fn from(input: Input) -> Self {
        Output {
            a: input.a
        }
    }
}

pub fn get_and_convert<I, O>(db_params: String) -> String {
    let input = get_data(db_params);
    let output = input.into();
    output.to_json()
}

Так что я попробовал что-то подобное (я новичокк макросам, чтобы код был очень неправильным, читайте его как псевдокод:

macro_rules! get_types {
    ("documents") => {
        (Document, JsonDocument)
    };
    ("themes") => {
        (Theme, JsonTheme)
    };
}

macro_rules! get_objs {
    ($x:expr, $y:expr, $params:expr) => {
        get_and_convert::<$x, $y>($params)
    };
}

используется как:

pub fn testmacro(args: String) {
    let (input_type, output_type) = get_types!("documents");
    let result = get_objs!(input_type, output_type, args);
}
...