Десериализовать файл, используя serde_json во время компиляции - PullRequest
0 голосов
/ 13 октября 2019

В начале моей программы я читаю данные из файла:

let file = std::fs::File::open("data/games.json").unwrap();
let data: Games = serde_json::from_reader(file).unwrap();

Я хотел бы знать, как можно было бы сделать это во время компиляции по следующим причинам:

  1. Производительность: не нужно десериализовать во время выполнения
  2. Переносимость: программу можно запустить на любом компьютере без необходимости иметь файл json, содержащий данные.

Мне также может быть полезно упомянуть, что данные могут быть прочитаны только, что означает, что решение может хранить их как статические.

1 Ответ

1 голос
/ 13 октября 2019

Это на самом деле очень просто, но приводит к некоторым потенциальным проблемам. Во-первых, мы должны иметь дело с чем-то. Мы хотим загрузить дерево объектов из файла или проанализировать это во время выполнения?

99% времени, для людей достаточно разбора при загрузке в static ref,так что я собираюсь дать вам это решение;В конце я укажу вам на «другую» версию, но это требует много дополнительной работы и зависит от домена.

Макрос (потому что он должен быть макросом)Вы ищете, чтобы иметь возможность включить файл во время компиляции находится в стандартной библиотеке: std::include_str!. Как следует из названия, он берет ваш файл во время компиляции и генерирует из него &'static str для использования. Затем вы можете делать с ним все, что захотите (например, анализировать его).

Оттуда можно просто использовать lazy_static! для генерации static refк нашему JSON Value (или к чему бы то ни было, на что вы решите пойти) для каждой используемой части программы. В вашем случае, например, это может выглядеть так:

const GAME_JSON:&str = include_str!("my/file.json");

#[derive(Serialize, Deserialize, Debug)]
struct Game {
    name: String
}

lazy_static! {
    static ref GAMES:Vec<Game> = serde_json::from_str(&GAME_JSON).unwrap();
}

При этом вам необходимо помнить о двух вещах:

  1. Это будет массово увеличивает размер файла, так как &str не сжимается никоим образом. Рассмотрим gzip
  2. Вам нужно беспокоиться об обычных проблемах, связанных с многопоточным доступом к одному и тому же static ref, но, поскольку он не является изменяемым, вам действительно нужно беспокоиться только о его части

Другой способ требует динамической генерации ваших объектов во время компиляции с использованием proc-macro. Как уже говорилось, я бы не рекомендовал этого, если у вас действительно нет действительно дорогих начальных затрат при анализе этого JSON;большинство людей этого не сделают, и в прошлый раз у меня это было, когда я имел дело с глубоко вложенными JSON-файлами с несколькими ГБ.

Ящики, на которые вы хотели обратить внимание: proc_macro2 и syn для кодапоколения;остальное очень похоже на то, как вы бы написали обычный метод.

...