use std::default::Default;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::Path;
use std::str::FromStr;
use toml;
use bindgen::ir::annotation::AnnotationSet;
pub use bindgen::rename::RenameRule;
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
#[derive(Debug, Clone, PartialEq)]
pub enum Language {
Cxx,
C,
}
impl FromStr for Language {
type Err = String;
fn from_str(s: &str) -> Result<Language, Self::Err> {
match s {
"cxx" => Ok(Language::Cxx),
"Cxx" => Ok(Language::Cxx),
"CXX" => Ok(Language::Cxx),
"cpp" => Ok(Language::Cxx),
"Cpp" => Ok(Language::Cxx),
"CPP" => Ok(Language::Cxx),
"c++" => Ok(Language::Cxx),
"C++" => Ok(Language::Cxx),
"c" => Ok(Language::C),
"C" => Ok(Language::C),
_ => Err(format!("Unrecognized Language: '{}'.", s)),
}
}
}
deserialize_enum_str!(Language);
#[derive(Debug, Clone, PartialEq)]
pub enum Braces {
SameLine,
NextLine,
}
impl FromStr for Braces {
type Err = String;
fn from_str(s: &str) -> Result<Braces, Self::Err> {
match s {
"SameLine" => Ok(Braces::SameLine),
"same_line" => Ok(Braces::SameLine),
"NextLine" => Ok(Braces::NextLine),
"next_line" => Ok(Braces::NextLine),
_ => Err(format!("Unrecognized Braces: '{}'.", s)),
}
}
}
deserialize_enum_str!(Braces);
#[derive(Debug, Clone, PartialEq)]
pub enum Layout {
Horizontal,
Vertical,
Auto,
}
impl FromStr for Layout {
type Err = String;
fn from_str(s: &str) -> Result<Layout, Self::Err> {
match s {
"Horizontal" => Ok(Layout::Horizontal),
"horizontal" => Ok(Layout::Horizontal),
"Vertical" => Ok(Layout::Vertical),
"vertical" => Ok(Layout::Vertical),
"Auto" => Ok(Layout::Auto),
"auto" => Ok(Layout::Auto),
_ => Err(format!("Unrecognized Layout: '{}'.", s)),
}
}
}
deserialize_enum_str!(Layout);
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct FunctionConfig {
pub prefix: Option<String>,
pub postfix: Option<String>,
pub args: Layout,
pub rename_args: Option<RenameRule>,
}
impl Default for FunctionConfig {
fn default() -> FunctionConfig {
FunctionConfig {
prefix: None,
postfix: None,
args: Layout::Auto,
rename_args: None,
}
}
}
impl FunctionConfig {
pub(crate) fn prefix(&self, annotations: &AnnotationSet) -> Option<String> {
if let Some(x) = annotations.atom("prefix") {
return x;
}
self.prefix.clone()
}
pub(crate) fn postfix(&self, annotations: &AnnotationSet) -> Option<String> {
if let Some(x) = annotations.atom("postfix") {
return x;
}
self.postfix.clone()
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct StructConfig {
pub rename_fields: Option<RenameRule>,
pub generic_template_specialization: bool,
pub derive_eq: bool,
pub derive_neq: bool,
pub derive_lt: bool,
pub derive_lte: bool,
pub derive_gt: bool,
pub derive_gte: bool,
}
impl Default for StructConfig {
fn default() -> StructConfig {
StructConfig {
rename_fields: None,
generic_template_specialization: true,
derive_eq: false,
derive_neq: false,
derive_lt: false,
derive_lte: false,
derive_gt: false,
derive_gte: false,
}
}
}
impl StructConfig {
pub(crate) fn derive_eq(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-eq") {
return x;
}
self.derive_eq
}
pub(crate) fn derive_neq(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-neq") {
return x;
}
self.derive_neq
}
pub(crate) fn derive_lt(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-lt") {
return x;
}
self.derive_lt
}
pub(crate) fn derive_lte(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-lte") {
return x;
}
self.derive_lte
}
pub(crate) fn derive_gt(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-gt") {
return x;
}
self.derive_gt
}
pub(crate) fn derive_gte(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-gte") {
return x;
}
self.derive_gte
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct EnumConfig {
pub rename_variants: Option<RenameRule>,
pub add_sentinel: bool,
pub prefix_with_name: bool,
}
impl Default for EnumConfig {
fn default() -> EnumConfig {
EnumConfig {
rename_variants: None,
add_sentinel: false,
prefix_with_name: false,
}
}
}
impl EnumConfig {
pub(crate) fn add_sentinel(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("add-sentinel") {
return x;
}
self.add_sentinel
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct ConstantConfig {
pub allow_static_const: bool,
}
impl Default for ConstantConfig {
fn default() -> ConstantConfig {
ConstantConfig {
allow_static_const: true,
}
}
}
#[derive( Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct ParseConfig {
pub parse_deps: bool,
pub include: Option<Vec<String>>,
pub exclude: Vec<String>,
pub expand: Vec<String>,
}
impl Default for ParseConfig {
fn default() -> ParseConfig {
ParseConfig {
parse_deps: false,
include: None,
exclude: Vec::new(),
expand: Vec::new(),
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct Config {
pub header: Option<String>,
pub trailer: Option<String>,
pub include_guard: Option<String>,
pub autogen_warning: Option<String>,
pub include_version: bool,
pub namespace: Option<String>,
pub namespaces: Option<Vec<String>>,
pub braces: Braces,
pub line_length: usize,
pub tab_width: usize,
pub language: Language,
pub parse: ParseConfig,
#[serde(rename = "fn")]
pub function: FunctionConfig,
#[serde(rename = "struct")]
pub structure: StructConfig,
#[serde(rename = "enum")]
pub enumeration: EnumConfig,
#[serde(rename = "const")]
pub constant: ConstantConfig,
pub defines: HashMap<String, String>,
pub documentation: bool,
}
impl Default for Config {
fn default() -> Config {
Config {
header: None,
trailer: None,
include_guard: None,
autogen_warning: None,
include_version: false,
namespace: None,
namespaces: None,
braces: Braces::SameLine,
line_length: 100,
tab_width: 2,
language: Language::Cxx,
parse: ParseConfig::default(),
function: FunctionConfig::default(),
structure: StructConfig::default(),
enumeration: EnumConfig::default(),
constant: ConstantConfig::default(),
defines: HashMap::new(),
documentation: true,
}
}
}
impl Config {
pub fn from_file(file_name: &str) -> Result<Config, String> {
fn read(file_name: &str) -> io::Result<String> {
let file = File::open(file_name)?;
let mut reader = BufReader::new(&file);
let mut contents = String::new();
reader.read_to_string(&mut contents)?;
Ok(contents)
}
let config_text = read(file_name).unwrap();
match toml::from_str::<Config>(&config_text) {
Ok(x) => Ok(x),
Err(e) => Err(format!("Couldn't parse config file: {}.", e)),
}
}
pub fn from_root_or_default(root: &Path) -> Config {
let c = root.join("cbindgen.toml");
if c.exists() {
Config::from_file(c.to_str().unwrap()).unwrap()
} else {
Config::default()
}
}
}