- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 297
Open
Labels
Description
As I'm working on a foreign data wrapper, I'll need to traverse the plan tree, and de-parse it to extract the information inside it. Currently, I'm manually implementing casting for the types I use:
pub trait PgNodeExt: PgNode {
    unsafe fn as_restrict_info(&self) -> &pg_sys::RestrictInfo;
    unsafe fn as_op_expr(&self) -> &pg_sys::OpExpr;
    unsafe fn as_var(&self) -> &pg_sys::Var;
    unsafe fn as_const(&self) -> &pg_sys::Const;
    unsafe fn as_relabel_type(&self) -> &pg_sys::RelabelType;
    unsafe fn as_bool_expr(&self) -> &pg_sys::BoolExpr;
}
impl<T: PgNode> PgNodeExt for T {
    unsafe fn as_restrict_info(&self) -> &pg_sys::RestrictInfo {
        if is_type(self, pg_sys::NodeTag_T_RestrictInfo) {
            unsafe { mem::transmute::<_, &pg_sys::RestrictInfo>(self) }
        } else {
            panic!("Not a RestrictInfo");
        }
    }
    unsafe fn as_op_expr(&self) -> &pg_sys::OpExpr {
        if is_type(self, pg_sys::NodeTag_T_OpExpr) {
            unsafe { mem::transmute::<_, &pg_sys::OpExpr>(self) }
        } else {
            panic!("Not a opexpr");
        }
    }
    unsafe fn as_bool_expr(&self) -> &pg_sys::BoolExpr {
        if is_type(self, pg_sys::NodeTag_T_BoolExpr) {
            unsafe { mem::transmute::<_, &pg_sys::BoolExpr>(self) }
        } else {
            panic!("Not a boolexpr");
        }
    }
    unsafe fn as_var(&self) -> &pg_sys::Var {
        if is_type(self, pg_sys::NodeTag_T_Var) {
            unsafe { mem::transmute::<_, &pg_sys::Var>(self) }
        } else {
            panic!("Not a var");
        }
    }
    unsafe fn as_const(&self) -> &pg_sys::Const {
        if is_type(self, pg_sys::NodeTag_T_Const) {
            unsafe { mem::transmute::<_, &pg_sys::Const>(self) }
        } else {
            panic!("Not a const");
        }
    }
    unsafe fn as_relabel_type(&self) -> &pg_sys::RelabelType {
        if is_type(self, pg_sys::NodeTag_T_RelabelType) {
            unsafe { mem::transmute::<_, &pg_sys::RelabelType>(self) }
        } else {
            panic!("Not a relabeltype");
        }
    }
}I'm wondering if it would be good to build this inside pg_sys? In the build.rs stage we can generate something like:
pub trait PgNodeExt: PgNode {
    unsafe fn as_<something>(&self) -> &pg_sys::Something; // for all PgNode types, panic if type mismatch
    unsafe fn as_<something>_mut(&mut self) -> &mut pg_sys::Something;
    unsafe fn try_as_<something>(&self) -> Option<&pg_sys::Something>; // return None if type mismatch
    unsafe fn try_as_<something>_mut(&mut self) -> Option<&mut pg_sys::Something>;
}
Or we can implement it as From and TryFrom.
impl <T: PgNode> From<&T> for <SomeNode> {} // repeat for all pgnodes
impl <T: PgNode> TryFrom<&T> for <SomeNode> {} // repeat for all pgnodes
I can have a try if this sounds like a good idea.