<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
use std::io::prelude::*;
use std::fs::File;
use std::cell::RefCell;
use std::collections::{HashSet, HashMap};

use syntax::ast::*;
use syntax::ptr::P;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::print::pprust::{NoAnn, print_crate};
use syntax::parse::token::{str_to_ident, Token, IdentStyle};
use syntax::codemap::{ExpnId, ExpnInfo, ExpnFormat, CompilerExpansionFormat, NameAndSpan, DUMMY_SP};
use syntax::feature_gate::GatedCfg;

use rustc_driver::driver::phase_1_parse_input;

use ::state::State;
use super::inner::Inner;

pub struct HsmGenerator {
    inner               : Inner,
    krate               : RefCell<Crate>,
    feature_gated_cfgs  : Vec<GatedCfg>,

}
impl HsmGenerator {
    pub fn new(prefix: bool) -> Self {
        let inner = Inner::new(prefix);
        let krate = RefCell::new(phase_1_parse_input(&inner.sess, inner.cfg.clone(), &inner.input));

        HsmGenerator {
            inner   : inner,
            krate   : krate,
            feature_gated_cfgs : Vec::new(),

        }
    }

    fn extctxt(&mut self) -> ExtCtxt {
        let mut cx = ExtCtxt::new(&self.inner.sess.parse_sess,
                                  self.inner.cfg.clone(),
                                  self.inner.ecfg(),
                                  &mut self.feature_gated_cfgs);
        cx.backtrace = ExpnId::from_u32(0);
        cx.codemap().record_expansion(
            ExpnInfo {
                call_site: self.krate.borrow().span,
                callee: NameAndSpan {
                    format: ExpnFormat::CompilerExpansion(CompilerExpansionFormat::PlacementIn),
                    allow_internal_unstable: true,
                    span: None,
                },
            }
        );
        cx
    }

    pub fn print(&self, file: &str) {
        let src_nam = self.inner.src_name.clone();
        let src = self.inner.sess.codemap().get_filemap(&src_nam[..])
                            .src
                            .as_ref()
                            .unwrap()
                            .as_bytes()
                            .to_vec();
        let mut rdr = &src[..];
        let mut out = Vec::new();
        let ann = NoAnn;
        {
            let out_w: &mut Write = &mut out;
            print_crate( self.inner.sess.codemap(),
                         self.inner.sess.diagnostic(),
                         &self.krate.borrow(),
                         src_nam,
                         &mut rdr,
                         box out_w,
                         &ann,
                         false).expect("Could not format crate");
        }
        // print!("{}", String::from_utf8(out).unwrap());
        let mut f = File::create(file).expect("Could not create file");
        f.write(&out).expect("Could not write to file");
    }

    pub fn create_event_enum(&mut self, hs: &HashSet<String>) {
        let en = {
            let cx = self.extctxt();
            let mut variants: Vec<P<Variant>> = Vec::new();
            for var_name in hs {
                let mut variant = cx.variant(
                    DUMMY_SP,
                    str_to_ident(var_name),
                    Vec::new()
                );
                variant.node.vis = Visibility::Inherited;
                variants.push(P(variant));
            }
            cx.item_enum(
                DUMMY_SP,
                str_to_ident("Events"),
                EnumDef{ variants: variants }
            ).map(|mut x| {
                x.vis = Visibility::Public;
                x.attrs.push(quote_attr!(&cx, #[derive(Debug, Clone)]));
                x
            })
        };
        self.krate.borrow_mut().module.items.push(en);
    }

    pub fn create_hsm_objects(&mut self, states: &HashSet<String>) {
        let x = {
            let cx = self.extctxt();
            let events = str_to_ident("Events");
            let st_str = str_to_ident("StateStruct");
            let st     = str_to_ident("States");
            let shr_dat= str_to_ident("SharedData");
            let states: Vec<TokenTree> = states
                .iter()
                .map(|st_nam| vec![Token::Ident(str_to_ident(st_nam), IdentStyle::Plain)])
                .collect::<Vec<_>>()
                .join(&Token::Comma)
                .into_iter()
                .map(|t| TtToken(DUMMY_SP, t))
                .collect();

            quote_item!(&cx,
                hsm_define_objects!($st_str, $st, $events, $shr_dat, (
                    $states
                ));
            ).unwrap()
        };
        self.krate.borrow_mut().module.items.push(x);
    }

    pub fn create_state_parent_impls(&mut self, hm: &HashMap<String, State>) {
        let x = {
            let cx = self.extctxt();
            let st = str_to_ident("States");
            let par_lst: Vec<TokenTree> = hm.values()
                .map(|state| vec![
                    Token::Ident(str_to_ident(state.name.as_ref().unwrap()), IdentStyle::Plain),
                    Token::RArrow,
                    Token::Ident(str_to_ident(if let Some(ref x) = state.parent {x} else {"None"} ), IdentStyle::Plain)
                ])
                .collect::<Vec<_>>()
                .join(&Token::Comma)
                .into_iter()
                .map(|t| TtToken(DUMMY_SP, t))
                .collect();
            quote_item!(&cx,
                hsm_state_parents!($st; $par_lst);
            ).unwrap()
        };
        self.krate.borrow_mut().module.items.push(x);
    }

    pub fn create_state_impls(&mut self, hm: &HashMap<String, State>) {
        let events = str_to_ident("Events");
        let states = str_to_ident("States");
        let shr_dat= str_to_ident("SharedData");
        for state in hm.values() {
            self.create_state_impl(state, &events, &states, &shr_dat);
        }
    }

    fn create_enter_exit_arm(cx: &ExtCtxt, opt_func: &Option<String>, evt_type: &str) -> Option<Arm> {
        if let &Some(ref func_nam) = opt_func {
            let func_ident = str_to_ident(func_nam);
            let evt_ident = str_to_ident(evt_type);
            Some(cx.arm(DUMMY_SP,
                   vec!(quote_pat!(&cx, hsm::Event::$evt_ident)),
                   quote_expr!(&cx, {
                        hsm_functions::$func_ident(shr_data, evt);
                        hsm::Action::Ignore
                   })
            ))
        } else { None }
    }

    fn create_state_impl(&mut self, state: &State, events: &Ident, states: &Ident, shr_dat: &Ident) {
        let x = {
            let cx = self.extctxt();
            let state_ident = str_to_ident(state.name.as_ref().unwrap());
            let mut arms: Vec<Arm> = Vec::new();
            Self::create_enter_exit_arm(&cx, &state.entry, "Enter").map(|x| arms.push(x));
            Self::create_enter_exit_arm(&cx, &state.exit, "Exit").map(|x| arms.push(x));
            for (trigger, target) in state.transitions.iter() {
                let target_ident = str_to_ident(target);
                let trigger_ident = str_to_ident(trigger);
                let pat = if trigger == "_" {
                    quote_pat!(&cx, $trigger_ident)
                } else {
                    quote_pat!(&cx, hsm::Event::User($events::$trigger_ident))
                };
                let trans = quote_expr!(&cx, $states::$target_ident);
                arms.push(cx.arm(DUMMY_SP,
                                 vec!(pat),
                                 quote_expr!(&cx, hsm_delayed_transition!(probe, { $trans }))
                ));
            };
            if !state.transitions.contains_key("_") {
                arms.push(cx.arm(DUMMY_SP,
                                 vec!(quote_pat!(&cx, _)),
                                 quote_expr!(&cx, hsm::Action::Parent)
                ));
            };
            let match_expr = cx.expr_match(DUMMY_SP, quote_expr!(&cx, evt), arms);
            quote_item!(&cx,
                impl hsm::State<$events, $states, $shr_dat> for $state_ident {
                    fn handle_event(&mut self, shr_data: &mut $shr_dat, evt: hsm::Event<$events>, probe: bool) -> hsm::Action<$states> {
                        $match_expr
                    }
                }
            ).unwrap()
        };
        self.krate.borrow_mut().module.items.push(x);
    }

    pub fn create_function_stubs(&mut self, hm: &HashMap<String, State>) {
        let events = str_to_ident("Events");
        let shr_dat= str_to_ident("SharedData");
        let mut functions = HashSet::new();
        hm.values().map(|s| {
            s.entry.as_ref().map(|x|
                functions.insert(x.to_string())
            );
            s.exit.as_ref().map(|x|
                functions.insert(x.to_string())
            )
        }).count();
        for func in functions {
            let it = {
                let cx = self.extctxt();
                let func_ident  = str_to_ident(&func);
                quote_item!(&cx,
                    fn $func_ident(shr_data: &mut $shr_dat, evt: hsm::Event<$events>) {
                        unimplemented!();
                    }
                ).unwrap().map(|mut x| {
                    x.vis = Visibility::Public;
                    x
                })
            };
            self.krate.borrow_mut().module.items.push(it);
            // println!("{}", func);
        }
    }
}
<commit_msg>take krate out from refcell<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
use std::io::prelude::*;
use std::fs::File;
use std::collections::{HashSet, HashMap};

use syntax::ast::*;
use syntax::ptr::P;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::print::pprust::{NoAnn, print_crate};
use syntax::parse::token::{str_to_ident, Token, IdentStyle};
use syntax::codemap::{ExpnId, ExpnInfo, ExpnFormat, CompilerExpansionFormat, NameAndSpan, DUMMY_SP};
use syntax::feature_gate::GatedCfg;

use rustc_driver::driver::phase_1_parse_input;

use ::state::State;
use super::inner::Inner;

pub struct HsmGenerator {
    inner               : Inner,
    krate               : Crate,
    feature_gated_cfgs  : Vec<GatedCfg>,

}
impl HsmGenerator {
    pub fn new(prefix: bool) -> Self {
        let inner = Inner::new(prefix);
        let krate = phase_1_parse_input(&inner.sess, inner.cfg.clone(), &inner.input);
        HsmGenerator {
            inner              : inner,
            krate              : krate,
            feature_gated_cfgs : Vec::new(),
        }
    }

    fn extctxt(&mut self) -> ExtCtxt {
        let mut cx = ExtCtxt::new(&self.inner.sess.parse_sess,
                                  self.inner.cfg.clone(),
                                  self.inner.ecfg(),
                                  &mut self.feature_gated_cfgs);
        cx.backtrace = ExpnId::from_u32(0);
        cx.codemap().record_expansion(
            ExpnInfo {
                call_site: self.krate.span,
                callee: NameAndSpan {
                    format: ExpnFormat::CompilerExpansion(CompilerExpansionFormat::PlacementIn),
                    allow_internal_unstable: true,
                    span: None,
                },
            }
        );
        cx
    }

    pub fn print(&self, file: &str) {
        let src_nam = self.inner.src_name.clone();
        let src = self.inner.sess.codemap().get_filemap(&src_nam[..])
                            .src
                            .as_ref()
                            .unwrap()
                            .as_bytes()
                            .to_vec();
        let mut rdr = &src[..];
        let mut out = Vec::new();
        let ann = NoAnn;
        {
            let out_w: &mut Write = &mut out;
            print_crate( self.inner.sess.codemap(),
                         self.inner.sess.diagnostic(),
                         &self.krate,
                         src_nam,
                         &mut rdr,
                         box out_w,
                         &ann,
                         false).expect("Could not format crate");
        }
        // print!("{}", String::from_utf8(out).unwrap());
        let mut f = File::create(file).expect("Could not create file");
        f.write(&out).expect("Could not write to file");
    }

    pub fn create_event_enum(&mut self, hs: &HashSet<String>) {
        let en = {
            let cx = self.extctxt();
            let mut variants: Vec<P<Variant>> = Vec::new();
            for var_name in hs {
                let mut variant = cx.variant(
                    DUMMY_SP,
                    str_to_ident(var_name),
                    Vec::new()
                );
                variant.node.vis = Visibility::Inherited;
                variants.push(P(variant));
            }
            cx.item_enum(
                DUMMY_SP,
                str_to_ident("Events"),
                EnumDef{ variants: variants }
            ).map(|mut x| {
                x.vis = Visibility::Public;
                x.attrs.push(quote_attr!(&cx, #[derive(Debug, Clone)]));
                x
            })
        };
        self.krate.module.items.push(en);
    }

    pub fn create_hsm_objects(&mut self, states: &HashSet<String>) {
        let x = {
            let cx = self.extctxt();
            let events = str_to_ident("Events");
            let st_str = str_to_ident("StateStruct");
            let st     = str_to_ident("States");
            let shr_dat= str_to_ident("SharedData");
            let states: Vec<TokenTree> = states
                .iter()
                .map(|st_nam| vec![Token::Ident(str_to_ident(st_nam), IdentStyle::Plain)])
                .collect::<Vec<_>>()
                .join(&Token::Comma)
                .into_iter()
                .map(|t| TtToken(DUMMY_SP, t))
                .collect();

            quote_item!(&cx,
                hsm_define_objects!($st_str, $st, $events, $shr_dat, (
                    $states
                ));
            ).unwrap()
        };
        self.krate.module.items.push(x);
    }

    pub fn create_state_parent_impls(&mut self, hm: &HashMap<String, State>) {
        let x = {
            let cx = self.extctxt();
            let st = str_to_ident("States");
            let par_lst: Vec<TokenTree> = hm.values()
                .map(|state| vec![
                    Token::Ident(str_to_ident(state.name.as_ref().unwrap()), IdentStyle::Plain),
                    Token::RArrow,
                    Token::Ident(str_to_ident(if let Some(ref x) = state.parent {x} else {"None"} ), IdentStyle::Plain)
                ])
                .collect::<Vec<_>>()
                .join(&Token::Comma)
                .into_iter()
                .map(|t| TtToken(DUMMY_SP, t))
                .collect();
            quote_item!(&cx,
                hsm_state_parents!($st; $par_lst);
            ).unwrap()
        };
        self.krate.module.items.push(x);
    }

    pub fn create_state_impls(&mut self, hm: &HashMap<String, State>) {
        let events = str_to_ident("Events");
        let states = str_to_ident("States");
        let shr_dat= str_to_ident("SharedData");
        for state in hm.values() {
            self.create_state_impl(state, &events, &states, &shr_dat);
        }
    }

    fn create_enter_exit_arm(cx: &ExtCtxt, opt_func: &Option<String>, evt_type: &str) -> Option<Arm> {
        if let &Some(ref func_nam) = opt_func {
            let func_ident = str_to_ident(func_nam);
            let evt_ident = str_to_ident(evt_type);
            Some(cx.arm(DUMMY_SP,
                   vec!(quote_pat!(&cx, hsm::Event::$evt_ident)),
                   quote_expr!(&cx, {
                        hsm_functions::$func_ident(shr_data, evt);
                        hsm::Action::Ignore
                   })
            ))
        } else { None }
    }

    fn create_state_impl(&mut self, state: &State, events: &Ident, states: &Ident, shr_dat: &Ident) {
        let x = {
            let cx = self.extctxt();
            let state_ident = str_to_ident(state.name.as_ref().unwrap());
            let mut arms: Vec<Arm> = Vec::new();
            Self::create_enter_exit_arm(&cx, &state.entry, "Enter").map(|x| arms.push(x));
            Self::create_enter_exit_arm(&cx, &state.exit, "Exit").map(|x| arms.push(x));
            for (trigger, target) in state.transitions.iter() {
                let target_ident = str_to_ident(target);
                let trigger_ident = str_to_ident(trigger);
                let pat = if trigger == "_" {
                    quote_pat!(&cx, $trigger_ident)
                } else {
                    quote_pat!(&cx, hsm::Event::User($events::$trigger_ident))
                };
                let trans = quote_expr!(&cx, $states::$target_ident);
                arms.push(cx.arm(DUMMY_SP,
                                 vec!(pat),
                                 quote_expr!(&cx, hsm_delayed_transition!(probe, { $trans }))
                ));
            };
            if !state.transitions.contains_key("_") {
                arms.push(cx.arm(DUMMY_SP,
                                 vec!(quote_pat!(&cx, _)),
                                 quote_expr!(&cx, hsm::Action::Parent)
                ));
            };
            let match_expr = cx.expr_match(DUMMY_SP, quote_expr!(&cx, evt), arms);
            quote_item!(&cx,
                impl hsm::State<$events, $states, $shr_dat> for $state_ident {
                    fn handle_event(&mut self, shr_data: &mut $shr_dat, evt: hsm::Event<$events>, probe: bool) -> hsm::Action<$states> {
                        $match_expr
                    }
                }
            ).unwrap()
        };
        self.krate.module.items.push(x);
    }

    pub fn create_function_stubs(&mut self, hm: &HashMap<String, State>) {
        let events = str_to_ident("Events");
        let shr_dat= str_to_ident("SharedData");
        let mut functions = HashSet::new();
        hm.values().map(|s| {
            s.entry.as_ref().map(|x|
                functions.insert(x.to_string())
            );
            s.exit.as_ref().map(|x|
                functions.insert(x.to_string())
            )
        }).count();
        for func in functions {
            let it = {
                let cx = self.extctxt();
                let func_ident  = str_to_ident(&func);
                quote_item!(&cx,
                    fn $func_ident(shr_data: &mut $shr_dat, evt: hsm::Event<$events>) {
                        unimplemented!();
                    }
                ).unwrap().map(|mut x| {
                    x.vis = Visibility::Public;
                    x
                })
            };
            self.krate.module.items.push(it);
            // println!("{}", func);
        }
    }
}
<|endoftext|>


<commit_before>//! RenderPass handling.

use crate::{format::Format, image, pso::PipelineStage, Backend};
use std::ops::Range;

/// Specifies the operation which will be applied at the beginning of a subpass.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AttachmentLoadOp {
    /// Preserve existing content in the attachment.
    Load,
    /// Clear the attachment.
    Clear,
    /// Attachment content will be undefined.
    DontCare,
}

///
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AttachmentStoreOp {
    /// Content written to the attachment will be preserved.
    Store,
    /// Attachment content will be undefined.
    DontCare,
}

/// Image layout of an attachment.
pub type AttachmentLayout = image::Layout;

/// Attachment operations.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AttachmentOps {
    /// Indicates how the data of the attachment will be loaded at first usage at
    /// the beginning of the subpass.
    pub load: AttachmentLoadOp,
    /// Whether or not data from the store operation will be preserved after the subpass.
    pub store: AttachmentStoreOp,
}

impl AttachmentOps {
    /// Specifies `DontCare` for both load and store op.
    pub const DONT_CARE: Self = AttachmentOps {
        load: AttachmentLoadOp::DontCare,
        store: AttachmentStoreOp::DontCare,
    };

    /// Specifies `Load` for load op and `Store` for store op.
    pub const PRESERVE: Self = AttachmentOps {
        load: AttachmentLoadOp::Load,
        store: AttachmentStoreOp::Store,
    };

    /// Convenience function to create a new `AttachmentOps`.
    pub fn new(load: AttachmentLoadOp, store: AttachmentStoreOp) -> Self {
        AttachmentOps { load, store }
    }

    /// A method to provide `AttachmentOps::DONT_CARE` to things that expect
    /// a default function rather than a value.
    #[cfg(feature = "serde")]
    fn whatever() -> Self {
        Self::DONT_CARE
    }
}

/// An `Attachment` is a description of a resource provided to a render subpass.
/// It includes things such as render targets, images that were produced from
/// previous subpasses, etc.
#[derive(Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Attachment {
    /// Attachment format
    ///
    /// In the most cases `format` is not `None`. It should be only used for
    /// creating dummy renderpasses, which are used as placeholder for compatible
    /// renderpasses.
    pub format: Option<Format>,
    /// Number of samples.
    pub samples: image::NumSamples,
    /// Load and store operations of the attachment
    pub ops: AttachmentOps,
    /// Load and store operations of the stencil aspect, if any
    #[cfg_attr(feature = "serde", serde(default = "AttachmentOps::whatever"))]
    pub stencil_ops: AttachmentOps,
    /// Initial and final image layouts of the renderpass.
    pub layouts: Range<AttachmentLayout>,
}

impl Attachment {
    /// Returns true if this attachment has some clear operations. This is useful
    /// when starting a render pass, since there has to be a clear value provided.
    pub fn has_clears(&self) -> bool {
        self.ops.load == AttachmentLoadOp::Clear || self.stencil_ops.load == AttachmentLoadOp::Clear
    }
}

/// Index of an attachment within a framebuffer/renderpass,
pub type AttachmentId = usize;
/// Reference to an attachment by index and expected image layout.
pub type AttachmentRef = (AttachmentId, AttachmentLayout);

/// Which other subpasses a particular subpass depends on.
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum SubpassRef {
    /// The subpass depends on something that was submitted to the
    /// queue before or after the render pass began.
    External,
    /// The subpass depends on another subpass with the given index,
    /// which must be less than or equal to the index of the current
    /// subpass. The index here refers to the corresponding
    /// `SubpassId` of a `Subpass`.
    Pass(usize),
}

/// Expresses a dependency between multiple subpasses. This is used
/// both to describe a source or destination subpass; data either
/// explicitly passes from this subpass to the next or from another
/// subpass into this one.
#[derive(Clone, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SubpassDependency {
    /// Other subpasses this one depends on.
    pub passes: Range<SubpassRef>,
    /// Other pipeline stages this subpass depends on.
    pub stages: Range<PipelineStage>,
    /// Resource accesses this subpass depends on.
    pub accesses: Range<image::Access>,
}

/// Description of a subpass for renderpass creation.
#[derive(Debug)]
pub struct SubpassDesc<'a> {
    /// Which attachments will be used as color buffers.
    pub colors: &'a [AttachmentRef],
    /// Which attachments will be used as depth/stencil buffers.
    pub depth_stencil: Option<&'a AttachmentRef>,
    /// Which attachments will be used as input attachments.
    pub inputs: &'a [AttachmentRef],
    /// Which attachments will be used as resolve destinations.
    ///
    /// The number of resolve attachments may be zero or equal to the number of color attachments.
    /// At the end of a subpass the color attachment will be resolved to the corresponding
    /// resolve attachment. The resolve attachment must not be multisampled.
    pub resolves: &'a [AttachmentRef],
    /// Attachments that are not used by the subpass but must be preserved to be
    /// passed on to subsequent passes.
    pub preserves: &'a [AttachmentId],
}

/// Index of a subpass.
pub type SubpassId = usize;

/// A sub-pass borrow of a pass.
#[derive(Debug)]
pub struct Subpass<'a, B: Backend> {
    /// Index of the subpass
    pub index: SubpassId,
    /// Main pass borrow.
    pub main_pass: &'a B::RenderPass,
}

impl<'a, B: Backend> Clone for Subpass<'a, B> {
    fn clone(&self) -> Self {
        Subpass {
            index: self.index,
            main_pass: self.main_pass,
        }
    }
}

impl<'a, B: Backend> PartialEq for Subpass<'a, B> {
    fn eq(&self, other: &Self) -> bool {
        self.index == other.index && self.main_pass as *const _ == other.main_pass as *const _
    }
}

impl<'a, B: Backend> Copy for Subpass<'a, B> {}
impl<'a, B: Backend> Eq for Subpass<'a, B> {}
<commit_msg>Add ATTACHMENT_UNUSED constant<commit_after>//! RenderPass handling.

use crate::{format::Format, image, pso::PipelineStage, Backend};
use std::ops::Range;

/// Specifies the operation which will be applied at the beginning of a subpass.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AttachmentLoadOp {
    /// Preserve existing content in the attachment.
    Load,
    /// Clear the attachment.
    Clear,
    /// Attachment content will be undefined.
    DontCare,
}

///
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AttachmentStoreOp {
    /// Content written to the attachment will be preserved.
    Store,
    /// Attachment content will be undefined.
    DontCare,
}

/// Image layout of an attachment.
pub type AttachmentLayout = image::Layout;

/// Attachment operations.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AttachmentOps {
    /// Indicates how the data of the attachment will be loaded at first usage at
    /// the beginning of the subpass.
    pub load: AttachmentLoadOp,
    /// Whether or not data from the store operation will be preserved after the subpass.
    pub store: AttachmentStoreOp,
}

impl AttachmentOps {
    /// Specifies `DontCare` for both load and store op.
    pub const DONT_CARE: Self = AttachmentOps {
        load: AttachmentLoadOp::DontCare,
        store: AttachmentStoreOp::DontCare,
    };

    /// Specifies `Load` for load op and `Store` for store op.
    pub const PRESERVE: Self = AttachmentOps {
        load: AttachmentLoadOp::Load,
        store: AttachmentStoreOp::Store,
    };

    /// Convenience function to create a new `AttachmentOps`.
    pub fn new(load: AttachmentLoadOp, store: AttachmentStoreOp) -> Self {
        AttachmentOps { load, store }
    }

    /// A method to provide `AttachmentOps::DONT_CARE` to things that expect
    /// a default function rather than a value.
    #[cfg(feature = "serde")]
    fn whatever() -> Self {
        Self::DONT_CARE
    }
}

/// An `Attachment` is a description of a resource provided to a render subpass.
/// It includes things such as render targets, images that were produced from
/// previous subpasses, etc.
#[derive(Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Attachment {
    /// Attachment format
    ///
    /// In the most cases `format` is not `None`. It should be only used for
    /// creating dummy renderpasses, which are used as placeholder for compatible
    /// renderpasses.
    pub format: Option<Format>,
    /// Number of samples.
    pub samples: image::NumSamples,
    /// Load and store operations of the attachment
    pub ops: AttachmentOps,
    /// Load and store operations of the stencil aspect, if any
    #[cfg_attr(feature = "serde", serde(default = "AttachmentOps::whatever"))]
    pub stencil_ops: AttachmentOps,
    /// Initial and final image layouts of the renderpass.
    pub layouts: Range<AttachmentLayout>,
}

impl Attachment {
    /// Returns true if this attachment has some clear operations. This is useful
    /// when starting a render pass, since there has to be a clear value provided.
    pub fn has_clears(&self) -> bool {
        self.ops.load == AttachmentLoadOp::Clear || self.stencil_ops.load == AttachmentLoadOp::Clear
    }
}

/// Index of an attachment within a framebuffer/renderpass,
pub type AttachmentId = usize;
/// Reference to an attachment by index and expected image layout.
pub type AttachmentRef = (AttachmentId, AttachmentLayout);
/// An AttachmentId that can be used instead of providing an attachment.
pub const ATTACHMENT_UNUSED: AttachmentId = !0;

/// Which other subpasses a particular subpass depends on.
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum SubpassRef {
    /// The subpass depends on something that was submitted to the
    /// queue before or after the render pass began.
    External,
    /// The subpass depends on another subpass with the given index,
    /// which must be less than or equal to the index of the current
    /// subpass. The index here refers to the corresponding
    /// `SubpassId` of a `Subpass`.
    Pass(usize),
}

/// Expresses a dependency between multiple subpasses. This is used
/// both to describe a source or destination subpass; data either
/// explicitly passes from this subpass to the next or from another
/// subpass into this one.
#[derive(Clone, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SubpassDependency {
    /// Other subpasses this one depends on.
    pub passes: Range<SubpassRef>,
    /// Other pipeline stages this subpass depends on.
    pub stages: Range<PipelineStage>,
    /// Resource accesses this subpass depends on.
    pub accesses: Range<image::Access>,
}

/// Description of a subpass for renderpass creation.
#[derive(Debug)]
pub struct SubpassDesc<'a> {
    /// Which attachments will be used as color buffers.
    pub colors: &'a [AttachmentRef],
    /// Which attachments will be used as depth/stencil buffers.
    pub depth_stencil: Option<&'a AttachmentRef>,
    /// Which attachments will be used as input attachments.
    pub inputs: &'a [AttachmentRef],
    /// Which attachments will be used as resolve destinations.
    ///
    /// The number of resolve attachments may be zero or equal to the number of color attachments.
    /// At the end of a subpass the color attachment will be resolved to the corresponding
    /// resolve attachment. The resolve attachment must not be multisampled.
    pub resolves: &'a [AttachmentRef],
    /// Attachments that are not used by the subpass but must be preserved to be
    /// passed on to subsequent passes.
    pub preserves: &'a [AttachmentId],
}

/// Index of a subpass.
pub type SubpassId = usize;

/// A sub-pass borrow of a pass.
#[derive(Debug)]
pub struct Subpass<'a, B: Backend> {
    /// Index of the subpass
    pub index: SubpassId,
    /// Main pass borrow.
    pub main_pass: &'a B::RenderPass,
}

impl<'a, B: Backend> Clone for Subpass<'a, B> {
    fn clone(&self) -> Self {
        Subpass {
            index: self.index,
            main_pass: self.main_pass,
        }
    }
}

impl<'a, B: Backend> PartialEq for Subpass<'a, B> {
    fn eq(&self, other: &Self) -> bool {
        self.index == other.index && self.main_pass as *const _ == other.main_pass as *const _
    }
}

impl<'a, B: Backend> Copy for Subpass<'a, B> {}
impl<'a, B: Backend> Eq for Subpass<'a, B> {}
<|endoftext|>


<commit_before>use crate::constants;
use reqwest::{
    RequestBuilder as ReqwestRequestBuilder,
    header::{AUTHORIZATION, CONTENT_TYPE, USER_AGENT, HeaderMap as Headers, HeaderValue},
    Url,
};
use reqwest::Client;
use super::{
    HttpError,
    routing::RouteInfo,
};

pub struct RequestBuilder<'a> {
    body: Option<&'a [u8]>,
    headers: Option<Headers>,
    route: RouteInfo<'a>,
}

impl<'a> RequestBuilder<'a> {
    pub fn new(route_info: RouteInfo<'a>) -> Self {
        Self {
            body: None,
            headers: None,
            route: route_info,
        }
    }

    pub fn build(self) -> Request<'a> {
        Request::new(self)
    }

    pub fn body(&mut self, body: Option<&'a [u8]>) -> &mut Self {
        self.body = body;

        self
    }

    pub fn headers(&mut self, headers: Option<Headers>) -> &mut Self {
        self.headers = headers;

        self
    }

    pub fn route(&mut self, route_info: RouteInfo<'a>) -> &mut Self {
        self.route = route_info;

        self
    }
}

#[derive(Clone, Debug)]
pub struct Request<'a> {
    pub(super) body: Option<&'a [u8]>,
    pub(super) headers: Option<Headers>,
    pub(super) route: RouteInfo<'a>,
}

impl<'a> Request<'a> {
    pub fn new(builder: RequestBuilder<'a>) -> Self {
        let RequestBuilder { body, headers, route } = builder;

        Self { body, headers, route }
    }

    pub fn build(&'a self, client: &Client, token: &str) -> Result<ReqwestRequestBuilder, HttpError> {
        let Request {
            body,
            headers: ref request_headers,
            route: ref route_info,
        } = *self;

        let (method, _, path) = route_info.deconstruct();

        let mut builder = client.request(
            method.reqwest_method(),
            Url::parse(&path)?,
        );

        if let Some(ref bytes) = body {
            builder = builder.body(Vec::from(*bytes));
        }

        let mut headers = Headers::with_capacity(3);
        headers.insert(USER_AGENT, HeaderValue::from_static(&constants::USER_AGENT));
        headers.insert(AUTHORIZATION,
            HeaderValue::from_str(&token).map_err(|e| HttpError::InvalidHeader(e))?);
        headers.insert(CONTENT_TYPE, HeaderValue::from_static(&"application/json"));

        if let Some(ref request_headers) = request_headers {
            headers.extend(request_headers.clone());
        }

        Ok(builder.headers(headers))
    }

    pub fn body_ref(&self) -> &Option<&'a [u8]> {
        &self.body
    }

    pub fn body_mut(&mut self) -> &mut Option<&'a [u8]> {
        &mut self.body
    }

    pub fn headers_ref(&self) -> &Option<Headers> {
        &self.headers
    }

    pub fn headers_mut(&mut self) -> &mut Option<Headers> {
        &mut self.headers
    }

    pub fn route_ref(&self) -> &RouteInfo<'_> {
        &self.route
    }

    pub fn route_mut(&mut self) -> &mut RouteInfo<'a> {
        &mut self.route
    }
}
<commit_msg>Specify Header's Content Length as `0` (#483)<commit_after>use crate::constants;
use reqwest::{
    RequestBuilder as ReqwestRequestBuilder,
    header::{AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT, HeaderMap as Headers, HeaderValue},
    Url,
};
use reqwest::Client;
use super::{
    HttpError,
    routing::RouteInfo,
};

pub struct RequestBuilder<'a> {
    body: Option<&'a [u8]>,
    headers: Option<Headers>,
    route: RouteInfo<'a>,
}

impl<'a> RequestBuilder<'a> {
    pub fn new(route_info: RouteInfo<'a>) -> Self {
        Self {
            body: None,
            headers: None,
            route: route_info,
        }
    }

    pub fn build(self) -> Request<'a> {
        Request::new(self)
    }

    pub fn body(&mut self, body: Option<&'a [u8]>) -> &mut Self {
        self.body = body;

        self
    }

    pub fn headers(&mut self, headers: Option<Headers>) -> &mut Self {
        self.headers = headers;

        self
    }

    pub fn route(&mut self, route_info: RouteInfo<'a>) -> &mut Self {
        self.route = route_info;

        self
    }
}

#[derive(Clone, Debug)]
pub struct Request<'a> {
    pub(super) body: Option<&'a [u8]>,
    pub(super) headers: Option<Headers>,
    pub(super) route: RouteInfo<'a>,
}

impl<'a> Request<'a> {
    pub fn new(builder: RequestBuilder<'a>) -> Self {
        let RequestBuilder { body, headers, route } = builder;

        Self { body, headers, route }
    }

    pub fn build(&'a self, client: &Client, token: &str) -> Result<ReqwestRequestBuilder, HttpError> {
        let Request {
            body,
            headers: ref request_headers,
            route: ref route_info,
        } = *self;

        let (method, _, path) = route_info.deconstruct();

        let mut builder = client.request(
            method.reqwest_method(),
            Url::parse(&path)?,
        );

        if let Some(ref bytes) = body {
            builder = builder.body(Vec::from(*bytes));
        }

        let mut headers = Headers::with_capacity(4);
        headers.insert(USER_AGENT, HeaderValue::from_static(&constants::USER_AGENT));
        headers.insert(AUTHORIZATION,
            HeaderValue::from_str(&token).map_err(|e| HttpError::InvalidHeader(e))?);
        headers.insert(CONTENT_TYPE, HeaderValue::from_static(&"application/json"));
        headers.insert(CONTENT_LENGTH, HeaderValue::from_static(&"0"));

        if let Some(ref request_headers) = request_headers {
            headers.extend(request_headers.clone());
        }

        Ok(builder.headers(headers))
    }

    pub fn body_ref(&self) -> &Option<&'a [u8]> {
        &self.body
    }

    pub fn body_mut(&mut self) -> &mut Option<&'a [u8]> {
        &mut self.body
    }

    pub fn headers_ref(&self) -> &Option<Headers> {
        &self.headers
    }

    pub fn headers_mut(&mut self) -> &mut Option<Headers> {
        &mut self.headers
    }

    pub fn route_ref(&self) -> &RouteInfo<'_> {
        &self.route
    }

    pub fn route_mut(&mut self) -> &mut RouteInfo<'a> {
        &mut self.route
    }
}
<|endoftext|>


<commit_before>//!  Image Processing Functions
use std::cmp;

use image:: {
    SubImage,
    GenericImage,
};

use buffer::Pixel;
use traits::Primitive;

pub use self::sample::FilterType;

pub use self::sample::FilterType:: {
    Triangle,
    Nearest,
    CatmullRom,
    Gaussian,
    Lanczos3
};

///Affine transformations
pub use self::affine:: {
    rotate90,
    rotate180,
    rotate270,
    flip_horizontal,
    flip_vertical,
};

///Image sampling
pub use self::sample:: {
    filter3x3,
    resize,
    blur,
    unsharpen,
};

///Color operations
pub use self::colorops:: {
    grayscale,
    invert,
    contrast,
    brighten,
};

mod affine;
mod colorops;
mod sample;

/// Return a mutable view into an image
pub fn crop<P: Primitive + 'static, T: Pixel<P>, I: GenericImage<T>>(
    image:  &mut I,
    x: u32,
    y: u32,
    width: u32,
    height: u32) -> SubImage<I> {

    let (iwidth, iheight) = image.dimensions();

    let x = cmp::min(x, iwidth);
    let y = cmp::min(y, iheight);

    let height = cmp::min(height, iheight - y);
    let width  = cmp::min(width, iwidth - x);

    SubImage::new(image, x, y, width, height)
}

/// Overlay an image at a given coordinate (x, y)
#[allow(deprecated)]
pub fn overlay<P: Primitive, T: Pixel<P>, I: GenericImage<T>>(
    bottom: &mut I,
    top: &I,
    x: u32,
    y: u32)  {
    let (top_width, top_height) = top.dimensions();
    let (bottom_width, bottom_height) = bottom.dimensions();

    //Crop our top image if we're going out of bounds
    let range_width = if x + top_width > bottom_width {
        bottom_width - x
    } else {
        top_width
    };

    let range_height = if y + top_height > bottom_height {
        bottom_height - y
    } else {
        top_height
    };

    for top_y in range(0, range_height) {
        for top_x in range(0, range_width) {
            let p = top.get_pixel(top_x, top_y);
            bottom.blend_pixel(x + top_x, y + top_y, p);
        }
    }
}

#[cfg(test)]
mod tests {

    use image::GenericImage;
    use buffer::ImageBuffer;
    use color::{Rgb};
    use super::overlay;

    #[test]
    ///Test that images written into other images works
    fn test_image_in_image() {
        let mut target = ImageBuffer::new(32, 32);
        let source = ImageBuffer::from_fn(16, 16, |_, _| {
            Rgb([255u8, 0, 0])
        });
        overlay(&mut target, &source, 0, 0);
        assert!(*target.get_pixel(0, 0) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(15, 0) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(16, 0) == Rgb([0u8, 0, 0]));
        assert!(*target.get_pixel(0, 15) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(0, 16) == Rgb([0u8, 0, 0]));
    }

    #[test]
    ///Test that images written outside of a frame doesn't blow up
    fn test_image_in_image_outside_of_bounds() {
        let mut target = ImageBuffer::new(32, 32);
        let source = ImageBuffer::from_fn(32, 32, |_, _| {
            Rgb([255u8, 0, 0])
        });
        overlay(&mut target, &source, 1, 1);
        assert!(*target.get_pixel(0, 0) == Rgb([0, 0, 0]));
        assert!(*target.get_pixel(1, 1) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(31, 31) == Rgb([255u8, 0, 0]));
    }

}
<commit_msg>update function to  "preferred" method<commit_after>//!  Image Processing Functions
use std::cmp;

use image:: {
    SubImage,
    GenericImage,
};

use buffer::Pixel;
use traits::Primitive;

pub use self::sample::FilterType;

pub use self::sample::FilterType:: {
    Triangle,
    Nearest,
    CatmullRom,
    Gaussian,
    Lanczos3
};

///Affine transformations
pub use self::affine:: {
    rotate90,
    rotate180,
    rotate270,
    flip_horizontal,
    flip_vertical,
};

///Image sampling
pub use self::sample:: {
    filter3x3,
    resize,
    blur,
    unsharpen,
};

///Color operations
pub use self::colorops:: {
    grayscale,
    invert,
    contrast,
    brighten,
};

mod affine;
mod colorops;
mod sample;

/// Return a mutable view into an image
pub fn crop<P: Primitive + 'static, T: Pixel<P>, I: GenericImage<T>>(
    image:  &mut I,
    x: u32,
    y: u32,
    width: u32,
    height: u32) -> SubImage<I> {

    let (iwidth, iheight) = image.dimensions();

    let x = cmp::min(x, iwidth);
    let y = cmp::min(y, iheight);

    let height = cmp::min(height, iheight - y);
    let width  = cmp::min(width, iwidth - x);

    SubImage::new(image, x, y, width, height)
}

/// Overlay an image at a given coordinate (x, y)
pub fn overlay<P: Primitive, T: Pixel<P>, I: GenericImage<T>>(
    bottom: &mut I,
    top: &I,
    x: u32,
    y: u32)  {
    let (top_width, top_height) = top.dimensions();
    let (bottom_width, bottom_height) = bottom.dimensions();

    //Crop our top image if we're going out of bounds
    let range_width = if x + top_width > bottom_width {
        bottom_width - x
    } else {
        top_width
    };

    let range_height = if y + top_height > bottom_height {
        bottom_height - y
    } else {
        top_height
    };

    for top_y in range(0, range_height) {
        for top_x in range(0, range_width) {
            let p = top.get_pixel(top_x, top_y);
            bottom.get_pixel_mut(x + top_x, y + top_y).blend(&p);
        }
    }
}

#[cfg(test)]
mod tests {

    use image::GenericImage;
    use buffer::ImageBuffer;
    use color::{Rgb};
    use super::overlay;

    #[test]
    ///Test that images written into other images works
    fn test_image_in_image() {
        let mut target = ImageBuffer::new(32, 32);
        let source = ImageBuffer::from_fn(16, 16, |_, _| {
            Rgb([255u8, 0, 0])
        });
        overlay(&mut target, &source, 0, 0);
        assert!(*target.get_pixel(0, 0) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(15, 0) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(16, 0) == Rgb([0u8, 0, 0]));
        assert!(*target.get_pixel(0, 15) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(0, 16) == Rgb([0u8, 0, 0]));
    }

    #[test]
    ///Test that images written outside of a frame doesn't blow up
    fn test_image_in_image_outside_of_bounds() {
        let mut target = ImageBuffer::new(32, 32);
        let source = ImageBuffer::from_fn(32, 32, |_, _| {
            Rgb([255u8, 0, 0])
        });
        overlay(&mut target, &source, 1, 1);
        assert!(*target.get_pixel(0, 0) == Rgb([0, 0, 0]));
        assert!(*target.get_pixel(1, 1) == Rgb([255u8, 0, 0]));
        assert!(*target.get_pixel(31, 31) == Rgb([255u8, 0, 0]));
    }

}
<|endoftext|>


<commit_before>//! `TyBuilder`, a helper for building instances of `Ty` and related types.

use std::iter;

use chalk_ir::{
    cast::{Cast, CastTo, Caster},
    fold::TypeFoldable,
    interner::HasInterner,
    AdtId, BoundVar, DebruijnIndex, Scalar,
};
use hir_def::{
    builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
    TypeAliasId,
};
use smallvec::SmallVec;

use crate::{
    consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
    ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
    TyDefId, TyExt, TyKind, ValueTyDefId,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParamKind {
    Type,
    Const(Ty),
}

/// This is a builder for `Ty` or anything that needs a `Substitution`.
pub struct TyBuilder<D> {
    /// The `data` field is used to keep track of what we're building (e.g. an
    /// ADT, a `TraitRef`, ...).
    data: D,
    vec: SmallVec<[GenericArg; 2]>,
    param_kinds: SmallVec<[ParamKind; 2]>,
}

impl<A> TyBuilder<A> {
    fn with_data<B>(self, data: B) -> TyBuilder<B> {
        TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
    }
}

impl<D> TyBuilder<D> {
    fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
        TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
    }

    fn build_internal(self) -> (D, Substitution) {
        assert_eq!(self.vec.len(), self.param_kinds.len());
        for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
            self.assert_match_kind(a, e);
        }
        let subst = Substitution::from_iter(Interner, self.vec);
        (self.data, subst)
    }

    pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
        let arg = arg.cast(Interner);
        let expected_kind = &self.param_kinds[self.vec.len()];
        let arg_kind = match arg.data(Interner) {
            chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
            chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
            chalk_ir::GenericArgData::Const(c) => {
                let c = c.data(Interner);
                ParamKind::Const(c.ty.clone())
            }
        };
        assert_eq!(*expected_kind, arg_kind);
        self.vec.push(arg);
        self
    }

    pub fn remaining(&self) -> usize {
        self.param_kinds.len() - self.vec.len()
    }

    pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
        // self.fill is inlined to make borrow checker happy
        let mut this = self;
        let other = this.param_kinds.iter().skip(this.vec.len());
        let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
            ParamKind::Type => {
                GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
                    .intern(Interner)
            }
            ParamKind::Const(ty) => GenericArgData::Const(
                ConstData {
                    value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
                    ty: ty.clone(),
                }
                .intern(Interner),
            )
            .intern(Interner),
        });
        this.vec.extend(filler.take(this.remaining()).casted(Interner));
        assert_eq!(this.remaining(), 0);
        this
    }

    pub fn fill_with_unknown(self) -> Self {
        // self.fill is inlined to make borrow checker happy
        let mut this = self;
        let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
            ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
            ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
        });
        this.vec.extend(filler.casted(Interner));
        assert_eq!(this.remaining(), 0);
        this
    }

    pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
        self.fill(|x| match x {
            ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
            ParamKind::Const(ty) => {
                GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
            }
        })
    }

    pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
        self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
        assert_eq!(self.remaining(), 0);
        self
    }

    pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
        assert!(self.vec.is_empty());
        assert!(parent_substs.len(Interner) <= self.param_kinds.len());
        self.extend(parent_substs.iter(Interner).cloned());
        self
    }

    fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
        for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
            self.assert_match_kind(&x.0, &x.1);
        }
        self.vec.extend(it);
    }

    fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
        match (a.data(Interner), e) {
            (chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
            | (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
            _ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds),
        }
    }
}

impl TyBuilder<()> {
    pub fn unit() -> Ty {
        TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
    }

    pub fn usize() -> Ty {
        TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
    }

    pub fn fn_ptr(sig: CallableSig) -> Ty {
        TyKind::Function(sig.to_fn_ptr()).intern(Interner)
    }

    pub fn builtin(builtin: BuiltinType) -> Ty {
        match builtin {
            BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
            BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
            BuiltinType::Str => TyKind::Str.intern(Interner),
            BuiltinType::Int(t) => {
                TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner)
            }
            BuiltinType::Uint(t) => {
                TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner)
            }
            BuiltinType::Float(t) => {
                TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner)
            }
        }
    }

    pub fn slice(argument: Ty) -> Ty {
        TyKind::Slice(argument).intern(Interner)
    }

    pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
        let params = generics(db.upcast(), def.into());
        params.placeholder_subst(db)
    }

    pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
        let def = def.into();
        let params = generics(db.upcast(), def);
        TyBuilder::new(
            (),
            params
                .iter()
                .map(|(id, data)| match data {
                    TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
                    TypeOrConstParamData::ConstParamData(_) => {
                        ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
                    }
                })
                .collect(),
        )
    }

    pub fn build(self) -> Substitution {
        let ((), subst) = self.build_internal();
        subst
    }
}

impl TyBuilder<hir_def::AdtId> {
    pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
        TyBuilder::subst_for_def(db, def).with_data(def)
    }

    pub fn fill_with_defaults(
        mut self,
        db: &dyn HirDatabase,
        mut fallback: impl FnMut() -> Ty,
    ) -> Self {
        let defaults = db.generic_defaults(self.data.into());
        for default_ty in defaults.iter().skip(self.vec.len()) {
            if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
                if x.is_unknown() {
                    self.vec.push(fallback().cast(Interner));
                    continue;
                }
            };
            // each default can depend on the previous parameters
            let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
            self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
        }
        self
    }

    pub fn build(self) -> Ty {
        let (adt, subst) = self.build_internal();
        TyKind::Adt(AdtId(adt), subst).intern(Interner)
    }
}

pub struct Tuple(usize);
impl TyBuilder<Tuple> {
    pub fn tuple(size: usize) -> TyBuilder<Tuple> {
        TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
    }

    pub fn build(self) -> Ty {
        let (Tuple(size), subst) = self.build_internal();
        TyKind::Tuple(size, subst).intern(Interner)
    }
}

impl TyBuilder<TraitId> {
    pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
        TyBuilder::subst_for_def(db, def).with_data(def)
    }

    pub fn build(self) -> TraitRef {
        let (trait_id, substitution) = self.build_internal();
        TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
    }
}

impl TyBuilder<TypeAliasId> {
    pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
        TyBuilder::subst_for_def(db, def).with_data(def)
    }

    pub fn build(self) -> ProjectionTy {
        let (type_alias, substitution) = self.build_internal();
        ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
    }
}

impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
    fn subst_binders(b: Binders<T>) -> Self {
        let param_kinds = b
            .binders
            .iter(Interner)
            .map(|x| match x {
                chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
                chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
                chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
            })
            .collect();
        TyBuilder::new(b, param_kinds)
    }

    pub fn build(self) -> T {
        let (b, subst) = self.build_internal();
        b.substitute(Interner, &subst)
    }
}

impl TyBuilder<Binders<Ty>> {
    pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
        TyBuilder::subst_binders(db.ty(def))
    }

    pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
        TyBuilder::subst_binders(db.impl_self_ty(def))
    }

    pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
        TyBuilder::subst_binders(db.value_ty(def))
    }
}
<commit_msg>Add `TyBuilder` method to build `Substitution` for generator<commit_after>//! `TyBuilder`, a helper for building instances of `Ty` and related types.

use std::iter;

use chalk_ir::{
    cast::{Cast, CastTo, Caster},
    fold::TypeFoldable,
    interner::HasInterner,
    AdtId, BoundVar, DebruijnIndex, Scalar,
};
use hir_def::{
    builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
    GenericDefId, TraitId, TypeAliasId,
};
use smallvec::SmallVec;

use crate::{
    consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
    ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
    TyDefId, TyExt, TyKind, ValueTyDefId,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParamKind {
    Type,
    Const(Ty),
}

/// This is a builder for `Ty` or anything that needs a `Substitution`.
pub struct TyBuilder<D> {
    /// The `data` field is used to keep track of what we're building (e.g. an
    /// ADT, a `TraitRef`, ...).
    data: D,
    vec: SmallVec<[GenericArg; 2]>,
    param_kinds: SmallVec<[ParamKind; 2]>,
}

impl<A> TyBuilder<A> {
    fn with_data<B>(self, data: B) -> TyBuilder<B> {
        TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
    }
}

impl<D> TyBuilder<D> {
    fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
        TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
    }

    fn build_internal(self) -> (D, Substitution) {
        assert_eq!(self.vec.len(), self.param_kinds.len());
        for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
            self.assert_match_kind(a, e);
        }
        let subst = Substitution::from_iter(Interner, self.vec);
        (self.data, subst)
    }

    pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
        let arg = arg.cast(Interner);
        let expected_kind = &self.param_kinds[self.vec.len()];
        let arg_kind = match arg.data(Interner) {
            chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
            chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
            chalk_ir::GenericArgData::Const(c) => {
                let c = c.data(Interner);
                ParamKind::Const(c.ty.clone())
            }
        };
        assert_eq!(*expected_kind, arg_kind);
        self.vec.push(arg);
        self
    }

    pub fn remaining(&self) -> usize {
        self.param_kinds.len() - self.vec.len()
    }

    pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
        // self.fill is inlined to make borrow checker happy
        let mut this = self;
        let other = this.param_kinds.iter().skip(this.vec.len());
        let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
            ParamKind::Type => {
                GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
                    .intern(Interner)
            }
            ParamKind::Const(ty) => GenericArgData::Const(
                ConstData {
                    value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
                    ty: ty.clone(),
                }
                .intern(Interner),
            )
            .intern(Interner),
        });
        this.vec.extend(filler.take(this.remaining()).casted(Interner));
        assert_eq!(this.remaining(), 0);
        this
    }

    pub fn fill_with_unknown(self) -> Self {
        // self.fill is inlined to make borrow checker happy
        let mut this = self;
        let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
            ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
            ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
        });
        this.vec.extend(filler.casted(Interner));
        assert_eq!(this.remaining(), 0);
        this
    }

    pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
        self.fill(|x| match x {
            ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
            ParamKind::Const(ty) => {
                GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
            }
        })
    }

    pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
        self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
        assert_eq!(self.remaining(), 0);
        self
    }

    pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
        assert!(self.vec.is_empty());
        assert!(parent_substs.len(Interner) <= self.param_kinds.len());
        self.extend(parent_substs.iter(Interner).cloned());
        self
    }

    fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
        for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
            self.assert_match_kind(&x.0, &x.1);
        }
        self.vec.extend(it);
    }

    fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
        match (a.data(Interner), e) {
            (chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
            | (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
            _ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds),
        }
    }
}

impl TyBuilder<()> {
    pub fn unit() -> Ty {
        TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
    }

    pub fn usize() -> Ty {
        TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
    }

    pub fn fn_ptr(sig: CallableSig) -> Ty {
        TyKind::Function(sig.to_fn_ptr()).intern(Interner)
    }

    pub fn builtin(builtin: BuiltinType) -> Ty {
        match builtin {
            BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
            BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
            BuiltinType::Str => TyKind::Str.intern(Interner),
            BuiltinType::Int(t) => {
                TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner)
            }
            BuiltinType::Uint(t) => {
                TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner)
            }
            BuiltinType::Float(t) => {
                TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner)
            }
        }
    }

    pub fn slice(argument: Ty) -> Ty {
        TyKind::Slice(argument).intern(Interner)
    }

    pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
        let params = generics(db.upcast(), def.into());
        params.placeholder_subst(db)
    }

    pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
        let def = def.into();
        let params = generics(db.upcast(), def);
        TyBuilder::new(
            (),
            params
                .iter()
                .map(|(id, data)| match data {
                    TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
                    TypeOrConstParamData::ConstParamData(_) => {
                        ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
                    }
                })
                .collect(),
        )
    }

    /// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
    ///
    /// A generator's substitution consists of:
    /// - generic parameters in scope on `parent`
    /// - resume type of generator
    /// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
    /// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
    /// in this order.
    ///
    /// This method prepopulates the builder with placeholder substitution of `parent`, so you
    /// should only push exactly 3 `GenericArg`s before building.
    pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
        let parent_subst = match parent.as_generic_def_id() {
            Some(parent) => generics(db.upcast(), parent).placeholder_subst(db),
            // Static initializers *may* contain generators.
            None => Substitution::empty(Interner),
        };
        let builder = TyBuilder::new(
            (),
            parent_subst
                .iter(Interner)
                .map(|arg| match arg.constant(Interner) {
                    Some(c) => ParamKind::Const(c.data(Interner).ty.clone()),
                    None => ParamKind::Type,
                })
                // These represent resume type, yield type, and return type of generator.
                .chain(std::iter::repeat(ParamKind::Type).take(3))
                .collect(),
        );
        builder.use_parent_substs(&parent_subst)
    }

    pub fn build(self) -> Substitution {
        let ((), subst) = self.build_internal();
        subst
    }
}

impl TyBuilder<hir_def::AdtId> {
    pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
        TyBuilder::subst_for_def(db, def).with_data(def)
    }

    pub fn fill_with_defaults(
        mut self,
        db: &dyn HirDatabase,
        mut fallback: impl FnMut() -> Ty,
    ) -> Self {
        let defaults = db.generic_defaults(self.data.into());
        for default_ty in defaults.iter().skip(self.vec.len()) {
            if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
                if x.is_unknown() {
                    self.vec.push(fallback().cast(Interner));
                    continue;
                }
            };
            // each default can depend on the previous parameters
            let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
            self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
        }
        self
    }

    pub fn build(self) -> Ty {
        let (adt, subst) = self.build_internal();
        TyKind::Adt(AdtId(adt), subst).intern(Interner)
    }
}

pub struct Tuple(usize);
impl TyBuilder<Tuple> {
    pub fn tuple(size: usize) -> TyBuilder<Tuple> {
        TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
    }

    pub fn build(self) -> Ty {
        let (Tuple(size), subst) = self.build_internal();
        TyKind::Tuple(size, subst).intern(Interner)
    }
}

impl TyBuilder<TraitId> {
    pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
        TyBuilder::subst_for_def(db, def).with_data(def)
    }

    pub fn build(self) -> TraitRef {
        let (trait_id, substitution) = self.build_internal();
        TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
    }
}

impl TyBuilder<TypeAliasId> {
    pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
        TyBuilder::subst_for_def(db, def).with_data(def)
    }

    pub fn build(self) -> ProjectionTy {
        let (type_alias, substitution) = self.build_internal();
        ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
    }
}

impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
    fn subst_binders(b: Binders<T>) -> Self {
        let param_kinds = b
            .binders
            .iter(Interner)
            .map(|x| match x {
                chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
                chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
                chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
            })
            .collect();
        TyBuilder::new(b, param_kinds)
    }

    pub fn build(self) -> T {
        let (b, subst) = self.build_internal();
        b.substitute(Interner, &subst)
    }
}

impl TyBuilder<Binders<Ty>> {
    pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
        TyBuilder::subst_binders(db.ty(def))
    }

    pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
        TyBuilder::subst_binders(db.impl_self_ty(def))
    }

    pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
        TyBuilder::subst_binders(db.value_ty(def))
    }
}
<|endoftext|>


<commit_before>//! # Environment life cycle APIs
//!
//! These APIs map to the life cycle of a specific "Agent" or self-contained
//! environment. If a Neon module is loaded multiple times (Web Workers, worker
//! threads), these API will be handle data associated with a specific instance.
//!
//! See the [N-API Lifecycle][npai-docs] documentation for more details.
//!
//! [napi-docs]: https://nodejs.org/api/n-api.html#n_api_environment_life_cycle_apis

use std::{
    any::Any,
    marker::PhantomData,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
};

use crate::{
    context::Context,
    event::Channel,
    handle::root::NapiRef,
    result::NeonResult,
    sys::{lifecycle, raw::Env, tsfn::ThreadsafeFunction},
    types::promise::NodeApiDeferred,
};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
/// Uniquely identifies an instance of the module
///
/// _Note_: Since `InstanceData` is created lazily, the order of `id` may not
/// reflect the order that instances were created.
pub(crate) struct InstanceId(u64);

impl InstanceId {
    fn next() -> Self {
        static NEXT_ID: AtomicU64 = AtomicU64::new(0);

        Self(NEXT_ID.fetch_add(1, Ordering::SeqCst))
    }
}

/// `InstanceData` holds Neon data associated with a particular instance of a
/// native module. If a module is loaded multiple times (e.g., worker threads), this
/// data will be unique per instance.
pub(crate) struct InstanceData {
    id: InstanceId,

    /// Used to free `Root` in the same JavaScript environment that created it
    ///
    /// _Design Note_: An `Arc` ensures the `ThreadsafeFunction` outlives the unloading
    /// of a module. Since it is unlikely that modules will be re-loaded frequently, this
    /// could be replaced with a leaked `&'static ThreadsafeFunction<NapiRef>`. However,
    /// given the cost of FFI, this optimization is omitted until the cost of an
    /// `Arc` is demonstrated as significant.
    drop_queue: Arc<ThreadsafeFunction<DropData>>,

    /// Shared `Channel` that is cloned to be returned by the `cx.channel()` method
    shared_channel: Channel,

    /// Table of user-defined global cells.
    globals: GlobalTable,
}

#[derive(Default)]
pub(crate) struct GlobalTable {
    cells: Vec<GlobalCell>,
}

pub(crate) type GlobalCellValue = Box<dyn Any + Send + 'static>;

pub(crate) enum GlobalCell {
    /// Uninitialized state.
    Uninit,
    /// Intermediate "dirty" state representing the middle of a `get_or_try_init` transaction.
    Trying,
    /// Fully initialized state.
    Init(GlobalCellValue),
}

impl GlobalCell {
    /// Establish the initial state at the beginning of the initialization protocol.
    /// This method ensures that re-entrant initialization always panics (i.e. when
    /// an existing `get_or_try_init` is in progress).
    fn pre_init<F>(&mut self, f: F)
    where
        F: FnOnce() -> GlobalCell,
    {
        match self {
            GlobalCell::Uninit => {
                *self = f();
            }
            GlobalCell::Trying => panic!("attempt to reinitialize Global during initialization"),
            GlobalCell::Init(_) => {}
        }
    }

    pub(crate) fn get<'cx, 'a, C>(cx: &'a mut C, id: usize) -> Option<&mut GlobalCellValue>
    where
        C: Context<'cx>,
    {
        let cell = InstanceData::globals(cx).get(id);
        match cell {
            GlobalCell::Init(ref mut b) => Some(b),
            _ => None,
        }
    }

    pub(crate) fn get_or_init<'cx, 'a, C>(
        cx: &'a mut C,
        id: usize,
        value: GlobalCellValue,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(value));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_init_with<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
        F: FnOnce() -> GlobalCellValue,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(f()));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_try_init<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> NeonResult<&mut GlobalCellValue>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        // Kick off a new transaction and drop it before getting the result.
        {
            let mut tx = TryInitTransaction::new(cx, id);
            tx.run(|cx| Ok(f(cx)?))?;
        }

        // If we're here, the transaction has succeeded, so get the result.
        Ok(GlobalCell::get(cx, id).unwrap())
    }
}

impl Default for GlobalCell {
    fn default() -> Self {
        GlobalCell::Uninit
    }
}

impl GlobalTable {
    pub(crate) fn get(&mut self, index: usize) -> &mut GlobalCell {
        if index >= self.cells.len() {
            self.cells.resize_with(index + 1, Default::default);
        }
        &mut self.cells[index]
    }
}

/// An RAII implementation of `GlobalCell::get_or_try_init`, which ensures that
/// the state of a cell is properly managed through all possible control paths.
/// As soon as the transaction begins, the cell is labelled as being in a dirty
/// state (`GlobalCell::Trying`), so that any additional re-entrant attempts to
/// initialize the cell will fail fast. The `Drop` implementation ensures that
/// after the transaction, the cell goes back to a clean state of either
/// `GlobalCell::Uninit` if it fails or `GlobalCell::Init` if it succeeds.
struct TryInitTransaction<'cx, 'a, C: Context<'cx>> {
    cx: &'a mut C,
    id: usize,
    _lifetime: PhantomData<&'cx ()>,
}

impl<'cx, 'a, C: Context<'cx>> TryInitTransaction<'cx, 'a, C> {
    fn new(cx: &'a mut C, id: usize) -> Self {
        let mut tx = Self {
            cx,
            id,
            _lifetime: PhantomData,
        };
        tx.cell().pre_init(|| GlobalCell::Trying);
        tx
    }

    /// _Post-condition:_ If this method returns an `Ok` result, the cell is in the
    /// `GlobalCell::Init` state.
    fn run<F>(&mut self, f: F) -> NeonResult<()>
    where
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        if self.is_trying() {
            let value = f(self.cx)?;
            *self.cell() = GlobalCell::Init(value);
        }
        Ok(())
    }

    fn cell(&mut self) -> &mut GlobalCell {
        InstanceData::globals(self.cx).get(self.id)
    }

    fn is_trying(&mut self) -> bool {
        if let GlobalCell::Trying = *self.cell() {
            true
        } else {
            false
        }
    }
}

impl<'cx, 'a, C: Context<'cx>> Drop for TryInitTransaction<'cx, 'a, C> {
    fn drop(&mut self) {
        if self.is_trying() {
            *self.cell() = GlobalCell::Uninit;
        }
    }
}

/// Wrapper for raw Node-API values to be dropped on the main thread
pub(crate) enum DropData {
    Deferred(NodeApiDeferred),
    Ref(NapiRef),
}

impl DropData {
    /// Drop a value on the main thread
    fn drop(env: Option<Env>, data: Self) {
        if let Some(env) = env {
            unsafe {
                match data {
                    DropData::Deferred(data) => data.leaked(env),
                    DropData::Ref(data) => data.unref(env),
                }
            }
        }
    }
}

impl InstanceData {
    /// Return the data associated with this module instance, lazily initializing if
    /// necessary.
    ///
    /// # Safety
    /// No additional locking (e.g., `Mutex`) is necessary because holding a
    /// `Context` reference ensures serialized access.
    pub(crate) fn get<'cx, C: Context<'cx>>(cx: &mut C) -> &mut InstanceData {
        let env = cx.env().to_raw();
        let data = unsafe { lifecycle::get_instance_data::<InstanceData>(env).as_mut() };

        if let Some(data) = data {
            return data;
        }

        let drop_queue = unsafe {
            let queue = ThreadsafeFunction::new(env, DropData::drop);
            queue.unref(env);
            queue
        };

        let shared_channel = {
            let mut channel = Channel::new(cx);
            channel.unref(cx);
            channel
        };

        let data = InstanceData {
            id: InstanceId::next(),
            drop_queue: Arc::new(drop_queue),
            shared_channel,
            globals: GlobalTable::default(),
        };

        unsafe { &mut *lifecycle::set_instance_data(env, data) }
    }

    /// Helper to return a reference to the `drop_queue` field of `InstanceData`
    pub(crate) fn drop_queue<'cx, C: Context<'cx>>(
        cx: &mut C,
    ) -> Arc<ThreadsafeFunction<DropData>> {
        Arc::clone(&InstanceData::get(cx).drop_queue)
    }

    /// Clones the shared channel and references it since new channels should start
    /// referenced, but the shared channel is unreferenced.
    pub(crate) fn channel<'cx, C: Context<'cx>>(cx: &mut C) -> Channel {
        let mut channel = InstanceData::get(cx).shared_channel.clone();
        channel.reference(cx);
        channel
    }

    /// Unique identifier for this instance of the module
    pub(crate) fn id<'cx, C: Context<'cx>>(cx: &mut C) -> InstanceId {
        InstanceData::get(cx).id
    }

    /// Helper to return a reference to the `globals` field of `InstanceData`.
    pub(crate) fn globals<'cx, C: Context<'cx>>(cx: &mut C) -> &mut GlobalTable {
        &mut InstanceData::get(cx).globals
    }
}
<commit_msg>Minor style cleanup for `TryInitTransaction::is_trying()`<commit_after>//! # Environment life cycle APIs
//!
//! These APIs map to the life cycle of a specific "Agent" or self-contained
//! environment. If a Neon module is loaded multiple times (Web Workers, worker
//! threads), these API will be handle data associated with a specific instance.
//!
//! See the [N-API Lifecycle][npai-docs] documentation for more details.
//!
//! [napi-docs]: https://nodejs.org/api/n-api.html#n_api_environment_life_cycle_apis

use std::{
    any::Any,
    marker::PhantomData,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
};

use crate::{
    context::Context,
    event::Channel,
    handle::root::NapiRef,
    result::NeonResult,
    sys::{lifecycle, raw::Env, tsfn::ThreadsafeFunction},
    types::promise::NodeApiDeferred,
};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
/// Uniquely identifies an instance of the module
///
/// _Note_: Since `InstanceData` is created lazily, the order of `id` may not
/// reflect the order that instances were created.
pub(crate) struct InstanceId(u64);

impl InstanceId {
    fn next() -> Self {
        static NEXT_ID: AtomicU64 = AtomicU64::new(0);

        Self(NEXT_ID.fetch_add(1, Ordering::SeqCst))
    }
}

/// `InstanceData` holds Neon data associated with a particular instance of a
/// native module. If a module is loaded multiple times (e.g., worker threads), this
/// data will be unique per instance.
pub(crate) struct InstanceData {
    id: InstanceId,

    /// Used to free `Root` in the same JavaScript environment that created it
    ///
    /// _Design Note_: An `Arc` ensures the `ThreadsafeFunction` outlives the unloading
    /// of a module. Since it is unlikely that modules will be re-loaded frequently, this
    /// could be replaced with a leaked `&'static ThreadsafeFunction<NapiRef>`. However,
    /// given the cost of FFI, this optimization is omitted until the cost of an
    /// `Arc` is demonstrated as significant.
    drop_queue: Arc<ThreadsafeFunction<DropData>>,

    /// Shared `Channel` that is cloned to be returned by the `cx.channel()` method
    shared_channel: Channel,

    /// Table of user-defined global cells.
    globals: GlobalTable,
}

#[derive(Default)]
pub(crate) struct GlobalTable {
    cells: Vec<GlobalCell>,
}

pub(crate) type GlobalCellValue = Box<dyn Any + Send + 'static>;

pub(crate) enum GlobalCell {
    /// Uninitialized state.
    Uninit,
    /// Intermediate "dirty" state representing the middle of a `get_or_try_init` transaction.
    Trying,
    /// Fully initialized state.
    Init(GlobalCellValue),
}

impl GlobalCell {
    /// Establish the initial state at the beginning of the initialization protocol.
    /// This method ensures that re-entrant initialization always panics (i.e. when
    /// an existing `get_or_try_init` is in progress).
    fn pre_init<F>(&mut self, f: F)
    where
        F: FnOnce() -> GlobalCell,
    {
        match self {
            GlobalCell::Uninit => {
                *self = f();
            }
            GlobalCell::Trying => panic!("attempt to reinitialize Global during initialization"),
            GlobalCell::Init(_) => {}
        }
    }

    pub(crate) fn get<'cx, 'a, C>(cx: &'a mut C, id: usize) -> Option<&mut GlobalCellValue>
    where
        C: Context<'cx>,
    {
        let cell = InstanceData::globals(cx).get(id);
        match cell {
            GlobalCell::Init(ref mut b) => Some(b),
            _ => None,
        }
    }

    pub(crate) fn get_or_init<'cx, 'a, C>(
        cx: &'a mut C,
        id: usize,
        value: GlobalCellValue,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(value));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_init_with<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
        F: FnOnce() -> GlobalCellValue,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(f()));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_try_init<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> NeonResult<&mut GlobalCellValue>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        // Kick off a new transaction and drop it before getting the result.
        {
            let mut tx = TryInitTransaction::new(cx, id);
            tx.run(|cx| Ok(f(cx)?))?;
        }

        // If we're here, the transaction has succeeded, so get the result.
        Ok(GlobalCell::get(cx, id).unwrap())
    }
}

impl Default for GlobalCell {
    fn default() -> Self {
        GlobalCell::Uninit
    }
}

impl GlobalTable {
    pub(crate) fn get(&mut self, index: usize) -> &mut GlobalCell {
        if index >= self.cells.len() {
            self.cells.resize_with(index + 1, Default::default);
        }
        &mut self.cells[index]
    }
}

/// An RAII implementation of `GlobalCell::get_or_try_init`, which ensures that
/// the state of a cell is properly managed through all possible control paths.
/// As soon as the transaction begins, the cell is labelled as being in a dirty
/// state (`GlobalCell::Trying`), so that any additional re-entrant attempts to
/// initialize the cell will fail fast. The `Drop` implementation ensures that
/// after the transaction, the cell goes back to a clean state of either
/// `GlobalCell::Uninit` if it fails or `GlobalCell::Init` if it succeeds.
struct TryInitTransaction<'cx, 'a, C: Context<'cx>> {
    cx: &'a mut C,
    id: usize,
    _lifetime: PhantomData<&'cx ()>,
}

impl<'cx, 'a, C: Context<'cx>> TryInitTransaction<'cx, 'a, C> {
    fn new(cx: &'a mut C, id: usize) -> Self {
        let mut tx = Self {
            cx,
            id,
            _lifetime: PhantomData,
        };
        tx.cell().pre_init(|| GlobalCell::Trying);
        tx
    }

    /// _Post-condition:_ If this method returns an `Ok` result, the cell is in the
    /// `GlobalCell::Init` state.
    fn run<F>(&mut self, f: F) -> NeonResult<()>
    where
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        if self.is_trying() {
            let value = f(self.cx)?;
            *self.cell() = GlobalCell::Init(value);
        }
        Ok(())
    }

    fn cell(&mut self) -> &mut GlobalCell {
        InstanceData::globals(self.cx).get(self.id)
    }

    fn is_trying(&mut self) -> bool {
        match self.cell() {
            GlobalCell::Trying => true,
            _ => false,
        }
    }
}

impl<'cx, 'a, C: Context<'cx>> Drop for TryInitTransaction<'cx, 'a, C> {
    fn drop(&mut self) {
        if self.is_trying() {
            *self.cell() = GlobalCell::Uninit;
        }
    }
}

/// Wrapper for raw Node-API values to be dropped on the main thread
pub(crate) enum DropData {
    Deferred(NodeApiDeferred),
    Ref(NapiRef),
}

impl DropData {
    /// Drop a value on the main thread
    fn drop(env: Option<Env>, data: Self) {
        if let Some(env) = env {
            unsafe {
                match data {
                    DropData::Deferred(data) => data.leaked(env),
                    DropData::Ref(data) => data.unref(env),
                }
            }
        }
    }
}

impl InstanceData {
    /// Return the data associated with this module instance, lazily initializing if
    /// necessary.
    ///
    /// # Safety
    /// No additional locking (e.g., `Mutex`) is necessary because holding a
    /// `Context` reference ensures serialized access.
    pub(crate) fn get<'cx, C: Context<'cx>>(cx: &mut C) -> &mut InstanceData {
        let env = cx.env().to_raw();
        let data = unsafe { lifecycle::get_instance_data::<InstanceData>(env).as_mut() };

        if let Some(data) = data {
            return data;
        }

        let drop_queue = unsafe {
            let queue = ThreadsafeFunction::new(env, DropData::drop);
            queue.unref(env);
            queue
        };

        let shared_channel = {
            let mut channel = Channel::new(cx);
            channel.unref(cx);
            channel
        };

        let data = InstanceData {
            id: InstanceId::next(),
            drop_queue: Arc::new(drop_queue),
            shared_channel,
            globals: GlobalTable::default(),
        };

        unsafe { &mut *lifecycle::set_instance_data(env, data) }
    }

    /// Helper to return a reference to the `drop_queue` field of `InstanceData`
    pub(crate) fn drop_queue<'cx, C: Context<'cx>>(
        cx: &mut C,
    ) -> Arc<ThreadsafeFunction<DropData>> {
        Arc::clone(&InstanceData::get(cx).drop_queue)
    }

    /// Clones the shared channel and references it since new channels should start
    /// referenced, but the shared channel is unreferenced.
    pub(crate) fn channel<'cx, C: Context<'cx>>(cx: &mut C) -> Channel {
        let mut channel = InstanceData::get(cx).shared_channel.clone();
        channel.reference(cx);
        channel
    }

    /// Unique identifier for this instance of the module
    pub(crate) fn id<'cx, C: Context<'cx>>(cx: &mut C) -> InstanceId {
        InstanceData::get(cx).id
    }

    /// Helper to return a reference to the `globals` field of `InstanceData`.
    pub(crate) fn globals<'cx, C: Context<'cx>>(cx: &mut C) -> &mut GlobalTable {
        &mut InstanceData::get(cx).globals
    }
}
<|endoftext|>