diff --git a/.gitignore b/.gitignore index 2261fa0..7719d7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ -/target +target logfile -/Cargo.lock +Cargo.lock + + +*.iml +.idea \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index cf7907d..30694b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,8 @@ name = "postgres_extension" version = "0.0.1" -authors = ["Daniel Fagnan "] +authors = ["Daniel Fagnan ", + "Jeff Davis "] [lib] name = "postgres_extension" diff --git a/Readme.md b/Readme.md index 1c950a1..f75a5cc 100644 --- a/Readme.md +++ b/Readme.md @@ -26,6 +26,9 @@ path = "https://github.com/thehydroimpulse/postgres-extension.rs" [dependencies.postgres_extension_macros] path = "https://github.com/thehydroimpulse/postgres-extension.rs" + +[dependencies.postgres_extension_plugin] +path = "https://github.com/thehydroimpulse/postgres-extension.rs" ``` ## Hello World! @@ -36,19 +39,11 @@ The first task is to link in the appropriate crates that we need: ```rust // lib.rs -#![feature(phase)] +#![feature(libc, custom_attribute, plugin)] +#![plugin(postgres_extension_plugin)] -extern crate postgres_extension; - -#[phase(plugin)] -extern crate postgres_extension_macros; ``` -The `phase` feature allows us to specify when to link the specified crate (compile-time? run-time?). - -The reason we need two crates is because syntax extensions need to link against `rustc` and `libsyntax`, the Rust compiler and parser (among other things), respectively. These are both fairly big crates and we only have a *compile-time* requirement on them. Meaning, when we run our program (or whatever final output we have) we never ever need access to those compiler crates. - -As a result, we'll use the `phase` feature to selectively choose to only link the macro crate during compilation and *not* during runtime. **Compatibility Checks:** @@ -60,7 +55,10 @@ So, continuing from the previous code we wrote: // lib.rs // ... -pg_module!(version: 90500) +extern crate postgres_extension; +#[macro_use] +extern crate postgres_extension_macros; +pg_module!(version: 90500); ``` We're just specifying that this extension is compatible with Postgres 9.5, that's it! @@ -88,7 +86,7 @@ pub fn is_zero(a: i32) -> i32 { Simply run `psql` (with whatever options you need/want). ```sql -CREATE FUNCTION is_zero(int4) RETURNS Boolean AS '/path/to/target/libis_zero-*.dylib' LANGUAGE c; +CREATE FUNCTION is_zero(int4) RETURNS Boolean AS '/path/to/target/libis_zero.so' LANGUAGE c; ``` Replacing the path with the real location to the `dylib`, of course. diff --git a/examples/is_zero/.gitignore b/examples/is_zero/.gitignore deleted file mode 100644 index 4fffb2f..0000000 --- a/examples/is_zero/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/examples/is_zero/Cargo.toml b/examples/is_zero/Cargo.toml index e8cce02..453d4ac 100644 --- a/examples/is_zero/Cargo.toml +++ b/examples/is_zero/Cargo.toml @@ -13,4 +13,7 @@ crate-type = ["dylib"] path = "../../" [dependencies.postgres_extension_macros] -path = "../../macros" +path = "../../macros/" + +[dependencies.postgres_extension_plugin] +path = "../../plugin/" \ No newline at end of file diff --git a/examples/is_zero/Readme.md b/examples/is_zero/Readme.md index f139c30..b86dec3 100644 --- a/examples/is_zero/Readme.md +++ b/examples/is_zero/Readme.md @@ -15,10 +15,11 @@ Simply build the library with Cargo: cargo build ``` -This will generate a new `libis_zero*.dylib` library ready to use in Postgres. +This will generate a new `libis_zero.so` library ready to use in Postgres. Now you can run `psql` to link against the library. ```sql -CREATE FUNCTION is_zero(int4) RETURNS Boolean AS '/path/to/target/libis_zero-*.dylib' LANGUAGE c; +CREATE FUNCTION is_zero(int4) RETURNS Boolean AS '/path/to/target/libis_zero.so' LANGUAGE c; ``` +refer \ No newline at end of file diff --git a/examples/is_zero/src/lib.rs b/examples/is_zero/src/lib.rs index 403cf0b..6939434 100644 --- a/examples/is_zero/src/lib.rs +++ b/examples/is_zero/src/lib.rs @@ -1,16 +1,15 @@ #![feature(libc, custom_attribute, plugin)] -#![plugin(postgres_extension_macros)] +#![plugin(postgres_extension_plugin)] extern crate postgres_extension; - #[macro_use] extern crate postgres_extension_macros; +pg_module!(version: 90500); -extern crate libc; -use libc::{c_int}; +extern crate libc; +use libc::{ c_int }; -pg_module!(version: 90500); #[pg_export] pub fn is_zero(a: c_int) -> c_int { @@ -22,6 +21,6 @@ pub fn is_zero(a: c_int) -> c_int { } #[pg_export] -pub fn echo_num(a: c_int) -> c_int { +pub fn return_num(a: c_int) -> c_int { return a } diff --git a/macros/.gitignore b/macros/.gitignore deleted file mode 100644 index 4fffb2f..0000000 --- a/macros/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 621bebc..1dbaf05 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -2,8 +2,9 @@ name = "postgres_extension_macros" version = "0.0.1" -authors = ["Daniel Fagnan "] +authors = ["Daniel Fagnan ", + "Jeff Davis "] [lib] name = "postgres_extension_macros" -crate-type = ["dylib", "rlib"] +crate-type = ["dylib"] diff --git a/macros/src/lib.rs b/macros/src/lib.rs index f09b034..f2dbb0d 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,57 +1,3 @@ -#![feature(plugin_registrar, quote, box_syntax, rustc_private)] -#![allow(unused_imports)] - -extern crate syntax; -extern crate syntax_ext; -extern crate rustc; -extern crate rustc_plugin; - -use rustc_plugin::Registry; -use syntax::ext::base::{MultiDecorator, MultiModifier}; -use syntax::parse::token::intern; -use rustc::hir::map::blocks::MaybeFnLike; - -use syntax::ext::base::{ExtCtxt, Annotatable}; -use syntax::codemap::Span; -use syntax::ptr::P; - -use syntax::ast::{Item, MetaItem}; -use syntax::attr; -use syntax_ext::deriving::generic::{combine_substructure, EnumMatching, FieldInfo, MethodDef, Struct, Substructure, TraitDef, ty}; -use syntax::parse::token::InternedString; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(intern("pg_export"), MultiModifier(box expand_pg_export)); -} - -pub fn expand_pg_export(cx: &mut ExtCtxt, span: Span, _: &MetaItem, item: Annotatable) -> Annotatable { - - //TODO: enforce func type check - // if !func.is_fn_like() { - // cx.span_err(span, "you can only export a function to PostgreSQL."); - // } - - match item { - Annotatable::Item(it) => { - let mut new_it = (*it).clone(); - new_it.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("no_mangle")))); - Annotatable::Item(P(new_it)) - } - Annotatable::ImplItem(it) => { - let mut new_it = (*it).clone(); - new_it.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("no_mangle")))); - Annotatable::ImplItem(P(new_it)) - } - Annotatable::TraitItem(tt) => { - let mut new_it = (*tt).clone(); - new_it.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("no_mangle")))); - Annotatable::TraitItem(P(new_it)) - } - } - -} - /// Postgres has a macro called `PG_MODULE_MAGIC` that is supposed /// to be called within extensions. This generates a bunch /// of metadata structures that Postgres reads to determine @@ -69,7 +15,7 @@ pub fn expand_pg_export(cx: &mut ExtCtxt, span: Span, _: &MetaItem, item: Annota #[macro_export] macro_rules! pg_module { (version: $vers:expr) => { - static mut Pg_magic_data: postgres_extension::Pg_magic_struct = + static mut PG_MAGIC_DATA: postgres_extension::Pg_magic_struct = postgres_extension::Pg_magic_struct { len: 0 as c_int, version: $vers, @@ -88,7 +34,7 @@ macro_rules! pg_module { use libc::{c_int}; unsafe { - Pg_magic_data = postgres_extension::Pg_magic_struct { + PG_MAGIC_DATA = postgres_extension::Pg_magic_struct { len: size_of::() as c_int, version: $vers / 100, funcmaxargs: 100, @@ -98,7 +44,7 @@ macro_rules! pg_module { float8byval: 1 }; - &Pg_magic_data + &PG_MAGIC_DATA } } } diff --git a/plugin/Cargo.toml b/plugin/Cargo.toml new file mode 100644 index 0000000..c0b8754 --- /dev/null +++ b/plugin/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "postgres_extension_plugin" +version = "0.0.1" +authors = ["Daniel Fagnan ", + "Jeff Davis "] + +[dependencies] + +[lib] +plugin = true +crate-type = ["dylib"] \ No newline at end of file diff --git a/plugin/src/lib.rs b/plugin/src/lib.rs new file mode 100644 index 0000000..7efd879 --- /dev/null +++ b/plugin/src/lib.rs @@ -0,0 +1,47 @@ +#![feature(plugin_registrar, box_syntax, rustc_private)] +#![allow(unused_imports)] + +extern crate syntax; +extern crate syntax_ext; +extern crate rustc; +extern crate rustc_plugin; + +use rustc_plugin::Registry; +use syntax::ext::base::{MultiDecorator, MultiModifier}; +use syntax::symbol::Symbol; +use rustc::hir::map::blocks::MaybeFnLike; + +use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::codemap::Span; +use syntax::ptr::P; + +use syntax::ast::{Item, MetaItem, TraitItem, ImplItem}; +use syntax::attr; +use syntax_ext::deriving::generic::{combine_substructure, EnumMatching, FieldInfo, MethodDef, Struct, Substructure, TraitDef, ty}; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_syntax_extension(Symbol::intern("pg_export"), MultiModifier(box expand_pg_export)); +} + +pub fn expand_pg_export(_cx: &mut ExtCtxt, span: Span, _: &MetaItem, item: Annotatable) -> Annotatable { + + match item { + Annotatable::Item(it) => { + let mut new_it = (*it).clone(); + new_it.attrs.push(attr::mk_attr_outer(span, attr::mk_attr_id(), attr::mk_word_item(Symbol::intern("no_mangle")))); + Annotatable::Item(P(new_it)) + } + Annotatable::ImplItem(it) => { + let mut new_it = (*it).clone(); + new_it.attrs.push(attr::mk_attr_outer(span, attr::mk_attr_id(), attr::mk_word_item(Symbol::intern("no_mangle")))); + Annotatable::ImplItem(P(new_it)) + } + Annotatable::TraitItem(tt) => { + let mut new_it = (*tt).clone(); + new_it.attrs.push(attr::mk_attr_outer(span, attr::mk_attr_id(), attr::mk_word_item(Symbol::intern("no_mangle")))); + Annotatable::TraitItem(P(new_it)) + } + } + +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 12eddc7..d69d5e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(non_camel_case_types)] + extern crate libc; extern crate core; @@ -9,10 +11,9 @@ pub const FUNC_MAX_ARGS: c_int = 100; type PGFunction = extern fn(FunctionCallInfo) -> Datum; type fmNodePtr = *mut c_void; -type fmAggrefPtr = *mut c_void; /// A trait that is implemented for all Postgres-compatible data types. -trait PgType {} +pub trait PgType {} #[allow(dead_code)] extern { @@ -458,6 +459,7 @@ pub struct FunctionCallInfoData { } pub struct FunctionCallInfo<'a> { + #[allow(dead_code)] ptr: *mut FunctionCallInfoData, marker: PhantomData<&'a FunctionCallInfoData> } @@ -466,11 +468,12 @@ pub struct FunctionCallInfo<'a> { /// a pointer-sized unsigned integer that acts like /// a pointer. pub struct Datum { + #[allow(dead_code)] val: usize } impl Datum { - pub fn new_str(value: &str) -> Datum { + pub fn new_str(_value: &str) -> Datum { // We need to allocate our string onto the heap // and with the custom `palloc` allocator. `palloc` // allocates memory into contexts such that they