Skip to content

Commit

Permalink
Create savvy-cli as clap dependency is so heavy
Browse files Browse the repository at this point in the history
  • Loading branch information
yutannihilation committed Sep 16, 2023
1 parent 7a8a3f8 commit 2033308
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 122 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[workspace]
members = ["savvy", "savvy-macro", "savvy-bindgen"]
members = ["savvy", "savvy-macro", "savvy-bindgen", "savvy-cli"]
resolver = "2"

[workspace.package]
version = "0.1.5"
version = "0.1.6"
edition = "2021"
authors = ["Hiroaki Yutani"]
license = "MIT"
Expand Down
1 change: 0 additions & 1 deletion savvy-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ repository.workspace = true
[dependencies]
proc-macro2 = "1"
quote = "1"
clap = { version = "4", features = ["derive"] }
syn = { version = "2", features = ["full", "extra-traits"] }
3 changes: 3 additions & 0 deletions savvy-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod parse_file;
mod savvy_fn;
mod savvy_impl;
mod utils;
Expand All @@ -10,3 +11,5 @@ pub use savvy_fn::{
pub use savvy_impl::SavvyImpl;

pub use utils::extract_docs;

pub use parse_file::{parse_file, parse_savvy_fn, parse_savvy_impl, read_file};
106 changes: 106 additions & 0 deletions savvy-bindgen/src/parse_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use std::{fs::File, io::Read, path::Path};

use syn::parse_quote;

use crate::{ParsedResult, SavvyFn, SavvyImpl};

pub fn parse_savvy_fn(item: &syn::Item) -> Option<SavvyFn> {
let func = match item {
syn::Item::Fn(func) => func,
_ => {
return None;
}
};

// Generate bindings only when the function is marked by #[savvy]
if func
.attrs
.iter()
.any(|attr| attr == &parse_quote!(#[savvy]))
{
Some(SavvyFn::from_fn(func))
} else {
None
}
}

pub fn parse_savvy_impl(item: &syn::Item) -> Vec<SavvyFn> {
let item_impl = match item {
syn::Item::Impl(item_impl) => item_impl,
_ => {
return Vec::new();
}
};

// Generate bindings only when the function is marked by #[savvy]
if item_impl
.attrs
.iter()
.any(|attr| attr == &parse_quote!(#[savvy]))
{
SavvyImpl::new(item_impl).fns
} else {
Vec::new()
}
}

fn is_marked(attrs: &[syn::Attribute]) -> bool {
attrs.iter().any(|attr| attr == &parse_quote!(#[savvy]))
}

pub fn read_file(path: &Path) -> String {
if !path.exists() {
eprintln!("{} does not exist", path.to_string_lossy());
std::process::exit(1);
}

let mut file = match File::open(path) {
Ok(file) => file,
Err(_) => {
eprintln!("Failed to read the specified file");
std::process::exit(2);
}
};

let mut content = String::new();
if file.read_to_string(&mut content).is_err() {
eprintln!("Failed to read the specified file");
std::process::exit(2);
};

content
}

pub fn parse_file(path: &Path) -> ParsedResult {
let ast = match syn::parse_str::<syn::File>(&read_file(path)) {
Ok(ast) => ast,
Err(_) => {
eprintln!("Failed to parse the specified file");
std::process::exit(3);
}
};

let mut result = ParsedResult {
bare_fns: Vec::new(),
impls: Vec::new(),
};

for item in ast.items {
match item {
syn::Item::Fn(item_fn) => {
if is_marked(item_fn.attrs.as_slice()) {
result.bare_fns.push(SavvyFn::from_fn(&item_fn))
}
}

syn::Item::Impl(item_impl) => {
if is_marked(item_impl.attrs.as_slice()) {
result.impls.push(SavvyImpl::new(&item_impl))
}
}
_ => continue,
};
}

result
}
13 changes: 13 additions & 0 deletions savvy-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "savvy-cli"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4", features = ["derive"] }
savvy-bindgen = { path = "../savvy-bindgen" }
127 changes: 8 additions & 119 deletions savvy-bindgen/src/main.rs → savvy-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
use clap::{Parser, Subcommand};
use savvy_fn::ParsedResult;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use syn::parse_quote;

mod savvy_fn;
mod savvy_impl;
mod utils;

use savvy_fn::make_c_header_file;
use savvy_fn::make_c_impl_file;
use savvy_fn::make_r_impl_file;
use savvy_fn::SavvyFn;
use savvy_impl::SavvyImpl;
use savvy_bindgen::make_c_header_file;
use savvy_bindgen::make_c_impl_file;
use savvy_bindgen::make_r_impl_file;

/// Generate C bindings and R bindings for a Rust library
#[derive(Parser, Debug)]
Expand Down Expand Up @@ -51,110 +41,9 @@ enum Commands {
},
}

pub fn parse_savvy_fn(item: &syn::Item) -> Option<SavvyFn> {
let func = match item {
syn::Item::Fn(func) => func,
_ => {
return None;
}
};

// Generate bindings only when the function is marked by #[savvy]
if func
.attrs
.iter()
.any(|attr| attr == &parse_quote!(#[savvy]))
{
Some(SavvyFn::from_fn(func))
} else {
None
}
}

pub fn parse_savvy_impl(item: &syn::Item) -> Vec<SavvyFn> {
let item_impl = match item {
syn::Item::Impl(item_impl) => item_impl,
_ => {
return Vec::new();
}
};

// Generate bindings only when the function is marked by #[savvy]
if item_impl
.attrs
.iter()
.any(|attr| attr == &parse_quote!(#[savvy]))
{
SavvyImpl::new(item_impl).fns
} else {
Vec::new()
}
}

fn is_marked(attrs: &[syn::Attribute]) -> bool {
attrs.iter().any(|attr| attr == &parse_quote!(#[savvy]))
}

fn read_file(path: &Path) -> String {
if !path.exists() {
eprintln!("{} does not exist", path.to_string_lossy());
std::process::exit(1);
}

let mut file = match File::open(path) {
Ok(file) => file,
Err(_) => {
eprintln!("Failed to read the specified file");
std::process::exit(2);
}
};

let mut content = String::new();
if file.read_to_string(&mut content).is_err() {
eprintln!("Failed to read the specified file");
std::process::exit(2);
};

content
}

fn parse_file(path: &Path) -> ParsedResult {
let ast = match syn::parse_str::<syn::File>(&read_file(path)) {
Ok(ast) => ast,
Err(_) => {
eprintln!("Failed to parse the specified file");
std::process::exit(3);
}
};

let mut result = ParsedResult {
bare_fns: Vec::new(),
impls: Vec::new(),
};

for item in ast.items {
match item {
syn::Item::Fn(item_fn) => {
if is_marked(item_fn.attrs.as_slice()) {
result.bare_fns.push(SavvyFn::from_fn(&item_fn))
}
}

syn::Item::Impl(item_impl) => {
if is_marked(item_impl.attrs.as_slice()) {
result.impls.push(SavvyImpl::new(&item_impl))
}
}
_ => continue,
};
}

result
}

// Parse DESCRIPTION file and get the package name
fn parse_description(path: &Path) -> Option<String> {
let content = read_file(path);
let content = savvy_bindgen::read_file(path);
for line in content.lines() {
if !line.starts_with("Package") {
continue;
Expand Down Expand Up @@ -196,7 +85,7 @@ fn update(path: &Path) {

let path_lib_rs = path.join(PATH_LIB_RS);
println!("Parsing {}", path_lib_rs.to_string_lossy());
let parsed_result = parse_file(path_lib_rs.as_path());
let parsed_result = savvy_bindgen::parse_file(path_lib_rs.as_path());

let path_c_header = path.join(PATH_C_HEADER);
println!("Writing {}", path_c_header.to_string_lossy());
Expand All @@ -216,15 +105,15 @@ fn main() {

match cli.command {
Commands::CHeader { file } => {
let parsed_result = parse_file(file.as_path());
let parsed_result = savvy_bindgen::parse_file(file.as_path());
println!("{}", make_c_header_file(&parsed_result));
}
Commands::CImpl { file } => {
let parsed_result = parse_file(file.as_path());
let parsed_result = savvy_bindgen::parse_file(file.as_path());
println!("{}", make_c_impl_file(&parsed_result, "%%PACKAGE_NAME%%"));
}
Commands::RImpl { file } => {
let parsed_result = parse_file(file.as_path());
let parsed_result = savvy_bindgen::parse_file(file.as_path());
println!("{}", make_r_impl_file(&parsed_result, "%%PACKAGE_NAME%%"));
}
Commands::Update { r_pkg_dir } => {
Expand Down

0 comments on commit 2033308

Please sign in to comment.