#![warn(missing_docs)]
#![warn(rustdoc::broken_intra_doc_links)]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use serde::de::Visitor;
use serde::{Deserialize, Serialize};
#[derive(Default, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Config<'c> {
#[doc(hidden)]
pub aliases: HashMap<Cow<'c, str>, Cow<'c, str>>,
pub schema_collect: SchemaCollect,
}
#[derive(Default)]
pub enum SchemaCollect {
All,
#[default]
NonInlined,
}
impl Serialize for SchemaCollect {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Self::All => serializer.serialize_str("all"),
Self::NonInlined => serializer.serialize_str("non_inlined"),
}
}
}
impl<'de> Deserialize<'de> for SchemaCollect {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct SchemaCollectVisitor;
impl<'d> Visitor<'d> for SchemaCollectVisitor {
type Value = SchemaCollect;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("expected str `all` or `non_inlined`")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if v == "all" {
Ok(SchemaCollect::All)
} else {
Ok(SchemaCollect::NonInlined)
}
}
}
deserializer.deserialize_str(SchemaCollectVisitor)
}
}
impl<'c> Config<'c> {
const NAME: &'static str = "fastapi-config.json";
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn alias_for(mut self, alias: &'c str, value: &'c str) -> Config<'c> {
self.aliases
.insert(Cow::Borrowed(alias), Cow::Borrowed(value));
self
}
pub fn schema_collect(mut self, schema_collect: SchemaCollect) -> Self {
self.schema_collect = schema_collect;
self
}
fn get_out_dir() -> Option<String> {
match std::env::var("OUT_DIR") {
Ok(out_dir) => Some(out_dir),
Err(_) => None,
}
}
pub fn write_to_file(&self) {
let json = serde_json::to_string(self).expect("Config must be JSON serializable");
let Some(out_dir) = Config::get_out_dir() else {
return;
};
match fs::write([&*out_dir, Config::NAME].iter().collect::<PathBuf>(), json) {
Ok(_) => (),
Err(error) => panic!("Failed to write config {}, error: {error}", Config::NAME),
};
}
#[doc(hidden)]
pub fn read_from_file() -> Config<'c> {
let Some(out_dir) = Config::get_out_dir() else {
return Config::default();
};
let str = match fs::read_to_string([&*out_dir, Config::NAME].iter().collect::<PathBuf>()) {
Ok(str) => str,
Err(error) => panic!("Failed to read config: {}, error: {error}", Config::NAME),
};
serde_json::from_str(&str).expect("Config muts be JSON deserializable")
}
}