use crate::cache;
use crate::probe_spec::ProbeSpecification;
use crate::provider_discovery::ProviderSpecification;
use askama::Template;
use failure::Fallible;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;
use std::path::PathBuf;
pub(crate) fn generate_provider_funcs(
cache_path: &Path,
provider: &ProviderSpecification,
) -> Fallible<PathBuf> {
let file_name = provider.static_provider_source_filename();
cache::cache_generated_file(cache_path, &file_name, |abs_path| {
generate_source_file(provider, abs_path)
})
}
#[derive(Template)]
#[template(path = "provider_wrapper.c", escape = "none")]
struct SourceFile<'a> {
package_name: &'a str,
package_version: &'a str,
trait_name: String,
trait_token_stream: String,
provider_name: &'a str,
provider_name_with_hash: String,
probes: Vec<Probe<'a>>,
}
impl<'a> SourceFile<'a> {
fn from_provider_spec<'b: 'a>(provider: &'b ProviderSpecification) -> SourceFile<'a> {
let probes: Vec<_> = provider
.probes
.iter()
.map(|probe| Probe::from_probe_spec(provider, probe))
.collect();
SourceFile {
package_name: env!("CARGO_PKG_NAME"),
package_version: env!("CARGO_PKG_VERSION"),
trait_name: provider.item_trait.ident.to_string(),
trait_token_stream: provider.token_stream.to_string(),
provider_name: &provider.name,
provider_name_with_hash: provider.name_with_hash(),
probes: probes,
}
}
}
struct Probe<'a> {
name: &'a str,
args: Vec<ProbeArg>,
}
impl<'a> Probe<'a> {
fn from_probe_spec<'b: 'a>(
provider: &'b ProviderSpecification,
probe: &'b ProbeSpecification,
) -> Probe<'a> {
let args: Vec<_> = probe
.args
.iter()
.map(|(name, typ)| ProbeArg::new(name.ident.to_string(), typ.to_string()))
.collect();
Probe {
name: &probe.name,
args: args,
}
}
}
struct ProbeArg {
name: String,
c_type: String,
}
impl ProbeArg {
fn new(name: String, typ: String) -> ProbeArg {
ProbeArg { name, c_type: typ }
}
}
fn generate_source_file(provider: &ProviderSpecification, abs_path: PathBuf) -> Fallible<PathBuf> {
let mut file = File::create(&abs_path)?;
let mut writer = BufWriter::new(&mut file);
write!(
writer,
r###"
/** This file automatically generated by {package_name} {package_version}. Do not edit
* this file.
*
* This file contains static wrappers for the probes defined in trait {trait_name}.
*
* The source code for that trait is:
*
* ```rust
* {trait_tokenstream}
* ```
*/
"###,
package_name = env!("CARGO_PKG_NAME"),
package_version = env!("CARGO_PKG_VERSION"),
trait_name = provider.item_trait.ident,
trait_tokenstream = provider.token_stream
)?;
write!(
writer,
r###"
#include <sys/sdt.h>
extern "C" {{
"###
)?;
write!(writer, "}}\n")?;
Ok(abs_path)
}