<commit_before>use std::path::Path;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::error::Error;

use ::subtitles::sentence::*;
use ::subtitles::syllable::Syllable;
use ::subtitles::metainfo::MetaInfo;
use ::subtitles::options::*;
use ::display::*;

use sdl2::render::Texture;
use sdl2::rect::Rect;

#[derive(Debug,Default)]
pub struct Subtitles {
    pub sentences:Vec<Sentence>,
    pub subtitles_options:Option<SubtitlesOptions>,
    pub meta_info:MetaInfo
}

/// subtitles : already stored Subtitles
/// sentence : Sentence to add to the subtitles
fn set_best_sentence_row(sentences:&[Sentence],sentence:&mut Sentence,default_sentence_options:SentenceOptions) {
    let sentence_options : SentenceOptions =
        sentence.sentence_options.unwrap_or(SentenceOptions::default()).or(default_sentence_options);
    let sentence_parameters = SentenceParameters::from(sentence_options);
    // TODO
    let mut best_row = 0u8 ;
    {
        let sentences_candidate = sentences.iter().filter(|sentence_candidate|{
            match (sentence.syllables.first(),sentence.syllables.last(),
                   sentence_candidate.syllables.first(),sentence_candidate.syllables.last()) {
                (None,_,_,_) | (_,None,_,_) | (_,_,None,_) | (_,_,_,None)  => false,
                (Some(ref first_syllable),Some(ref last_syllable),
                 Some(ref first_syllable_candidate),Some(ref last_syllable_candidate)) => {
                    let sentence_candidate_options : SentenceOptions =
                        sentence_candidate.sentence_options.unwrap_or(SentenceOptions::default()).or(default_sentence_options);
                    let sentence_candidate_parameters = SentenceParameters::from(sentence_candidate_options);
                    let first_frame = first_syllable.begin
                        .saturating_sub(sentence_parameters.transition_time as u32);
                    let last_frame = last_syllable.end
                        .saturating_add(sentence_parameters.transition_time as u32);
                    let first_frame_candidate = first_syllable_candidate.begin
                        .saturating_sub(sentence_candidate_parameters.transition_time as u32);
                    let last_frame_candidate = last_syllable_candidate.end
                        .saturating_add(sentence_candidate_parameters.transition_time as u32);
                    if (last_frame_candidate >= first_frame  && last_frame_candidate <= last_frame ) ||
                       (first_frame_candidate >= first_frame && first_frame_candidate <= last_frame) ||
                       (last_frame >= first_frame_candidate  && last_frame <= last_frame_candidate ) ||
                       (first_frame >= first_frame_candidate && first_frame <= last_frame_candidate) {
                        true
                    } else {
                        false
                    }
                }
            }
        });
        let mut taken = vec![];
        for sentence in sentences_candidate {
            match sentence.position {
                Position::Row(i) => {taken.push(i);},
                _ => {}
            }
        };
        while taken.iter().any(|v| *v == best_row) {
            best_row = best_row + 1 ;
        }
    }
    sentence.position = Position::Row(best_row);
}

impl Subtitles {
    pub fn load_from_lyr_frm<P:AsRef<Path>>(lyr:P,frm:P) -> Result<Subtitles,String> {
        let frm : &Path = frm.as_ref();
        let lyr : &Path = lyr.as_ref();
        let mut subtitles = Subtitles::default();
        let lyr_file = try!(File::open(lyr).map_err(|e| e.description().to_string() ));
        let frm_file = try!(File::open(frm).map_err(|e| e.description().to_string() ));
        let lyr_file = BufReader::new(&lyr_file);
        let frm_file = BufReader::new(&frm_file);
        for (line_number,lyr_line) in lyr_file.lines().enumerate() {
            let lyr_line = try!(
                lyr_line.map_err(|e|
                    format!("IoError when reading {} at line {} : '{}'",
                            lyr.display(),
                            line_number,
                            e.description())
                )
            );
            let mut current_sentence_options = SentenceOptions::default();
            if (!lyr_line.starts_with("%") && !lyr_line.is_empty()) {
                let mut syllables : Vec<_> = lyr_line.split('&')
                                                     .map(|s|
                                                     Syllable {
                                                         text:s.to_string(),
                                                         begin:0,
                                                         end:0,
                                                         syllable_options:current_sentence_options.syllable_options,
                                                     })
                                                     .collect::<Vec<_>>();
                if (lyr_line.starts_with("&")) {
                    syllables.remove(0);
                };
                let sentence = Sentence {
                    syllables : syllables,
                    position : Position::Row(0),
                    sentence_options : None
                };
                subtitles.sentences.push(sentence);
            } else if lyr_line.starts_with("%color") {
                let colors : Vec<_> = lyr_line.split_whitespace().collect();
                if colors.len() == 4 {

                } else {
                    error!("Invalid %color syntax when reading {} at line {} : '{}'",lyr.display(),line_number,lyr_line);
                }
            };
        }
        let mut frames : Vec<(u32,u32)> = vec!();
        for (line_number,frm_line) in frm_file.lines().enumerate() {
            let frm_line = try!(
                frm_line.map_err(|e|
                    format!("IoError when reading {} at line {} : '{}'",
                            frm.display(),
                            line_number,
                            e.description())
                )
            );
            if !frm_line.trim().is_empty() {
                let line_frames : Result<Vec<_>,_> = frm_line.split(' ')
                                                     .map(|s| s.parse::<u32>())
                                                     .collect();
                let begin_end = line_frames.map_err(|e| {
                    format!("{}",e)
                }).and_then(|line_frames| {
                    match (line_frames.get(0),line_frames.get(1),line_frames.get(2)) {
                        (Some(&begin),Some(&end),None) => {
                            Ok((begin,end))
                        },
                        (None,_,_) | (_,None,_) => {
                            Err(format!("Error while parsing frm file '{}' at line {}, not enough values",frm.display(),line_number))
                        },
                        (_,_,Some(_)) => {
                            Err(format!("Error while parsing frm file '{}' at line {}, too many values",frm.display(),line_number))
                        }
                    }
                });
                let begin_end = try!(begin_end);
                frames.push(begin_end);
            } else {
                warn!("empty line {} in frm file '{}'",line_number,frm.display());
            }
        };
        let mut frame_iter = frames.iter();
        'sentences: for sentence in subtitles.sentences.iter_mut() {
            for syllable in sentence.syllables.iter_mut() {
                match frame_iter.next() {
                    Some(&(begin,end)) => {
                        syllable.begin = begin ;
                        syllable.end = end ;
                    },
                    None => {
                        break 'sentences;
                    }
                }
            }
        };
        let default_sentence_options : SentenceOptions =
            subtitles.subtitles_options.as_ref().map(
                |ref sub_opts| sub_opts.sentence_options.unwrap_or(SentenceOptions::default())
            ).unwrap_or(SentenceOptions::default());
        for i in 0..subtitles.sentences.len() {
            let (first_half,mut last_half) = subtitles.sentences.split_at_mut(i);
            let sentence = last_half.first_mut().expect("Unexpected None for subtitles last_half");
            set_best_sentence_row(first_half,sentence,default_sentence_options);
        }
        Ok(subtitles)
    }

    /// Note that it will use the render_target used by the renderer,
    /// meaning that it can be a texture or the window depending on what
    /// is used with Displayer
    fn print_subtitle_frame_at(&self,displayer:&mut Displayer,frame_number:u32) -> Result<(),String> {
        let frame = ::display::frame::Frame::from_subtitles(self, frame_number);
        frame.draw(displayer);
        Ok(())
    }

    pub fn get_texture_at_frame(&self,displayer:&mut Displayer,frame:u32) -> Result<Texture,String> {
        use sdl2::pixels::Color;
        use sdl2::pixels::PixelFormatEnum::ARGB8888;
        fn ceil_power_of_2(v:f64) -> u32 {
            2u32.pow(v.log2().ceil() as u32)
        };
        let (renderer_w,renderer_h) = try!(displayer.sdl_renderer().output_size());
        let texture_width = ceil_power_of_2(renderer_w as f64);
        let texture_height = ceil_power_of_2(renderer_h as f64);
        let mut texture = displayer.sdl_renderer().create_texture_target(ARGB8888,texture_width,texture_height)
            .expect("Failed to create texture");
        texture.set_blend_mode(::sdl2::render::BlendMode::Blend);
        if let Some(ref mut render_target) = displayer.sdl_renderer_mut().render_target() {
            let old_texture = render_target.set(texture).expect("Failed to set texture as target");
            debug_assert!(old_texture.is_none());
        } else {
            error!("Render target are not supported with this GC driver");
            return Err("Render target are not supported with this GC driver".to_string());
        };
        let res = {
            displayer.sdl_renderer_mut().set_viewport(Some(Rect::new(0,0,renderer_w,renderer_h)));
            displayer.sdl_renderer_mut().set_draw_color(Color::RGBA(0,0,0,0));
            // make the texture transparent
            displayer.sdl_renderer_mut().clear();
            // draw subtitles on current render target
            self.print_subtitle_frame_at(displayer,frame)
        };
        displayer.sdl_renderer_mut().set_viewport(None);
        let new_texture = {
            if let Some(ref mut render_target) = displayer.sdl_renderer_mut().render_target() {
                render_target.reset()
                    .expect("Failed to reset render_target")
                    .expect("Failed to retrive texture from renderer")
            } else {
                error!("An unknown error happened; Failed to get render_target from renderer");
                panic!("Failed to get render_target from renderer")
            }
        };
        res.and(Ok(new_texture))
    }
}
<commit_msg>.lyr Color parsing<commit_after>use std::path::Path;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::error::Error;

use ::subtitles::sentence::*;
use ::subtitles::syllable::Syllable;
use ::subtitles::metainfo::MetaInfo;
use ::subtitles::options::*;
use ::display::*;

use sdl2::render::Texture;
use sdl2::rect::Rect;

#[derive(Debug,Default)]
pub struct Subtitles {
    pub sentences:Vec<Sentence>,
    pub subtitles_options:Option<SubtitlesOptions>,
    pub meta_info:MetaInfo
}

/// subtitles : already stored Subtitles
/// sentence : Sentence to add to the subtitles
fn set_best_sentence_row(sentences:&[Sentence],sentence:&mut Sentence,default_sentence_options:SentenceOptions) {
    let sentence_options : SentenceOptions =
        sentence.sentence_options.unwrap_or(SentenceOptions::default()).or(default_sentence_options);
    let sentence_parameters = SentenceParameters::from(sentence_options);
    // TODO
    let mut best_row = 0u8 ;
    {
        let sentences_candidate = sentences.iter().filter(|sentence_candidate|{
            match (sentence.syllables.first(),sentence.syllables.last(),
                   sentence_candidate.syllables.first(),sentence_candidate.syllables.last()) {
                (None,_,_,_) | (_,None,_,_) | (_,_,None,_) | (_,_,_,None)  => false,
                (Some(ref first_syllable),Some(ref last_syllable),
                 Some(ref first_syllable_candidate),Some(ref last_syllable_candidate)) => {
                    let sentence_candidate_options : SentenceOptions =
                        sentence_candidate.sentence_options.unwrap_or(SentenceOptions::default()).or(default_sentence_options);
                    let sentence_candidate_parameters = SentenceParameters::from(sentence_candidate_options);
                    let first_frame = first_syllable.begin
                        .saturating_sub(sentence_parameters.transition_time as u32);
                    let last_frame = last_syllable.end
                        .saturating_add(sentence_parameters.transition_time as u32);
                    let first_frame_candidate = first_syllable_candidate.begin
                        .saturating_sub(sentence_candidate_parameters.transition_time as u32);
                    let last_frame_candidate = last_syllable_candidate.end
                        .saturating_add(sentence_candidate_parameters.transition_time as u32);
                    if (last_frame_candidate >= first_frame  && last_frame_candidate <= last_frame ) ||
                       (first_frame_candidate >= first_frame && first_frame_candidate <= last_frame) ||
                       (last_frame >= first_frame_candidate  && last_frame <= last_frame_candidate ) ||
                       (first_frame >= first_frame_candidate && first_frame <= last_frame_candidate) {
                        true
                    } else {
                        false
                    }
                }
            }
        });
        let mut taken = vec![];
        for sentence in sentences_candidate {
            match sentence.position {
                Position::Row(i) => {taken.push(i);},
                _ => {}
            }
        };
        while taken.iter().any(|v| *v == best_row) {
            best_row = best_row + 1 ;
        }
    }
    sentence.position = Position::Row(best_row);
}

impl Subtitles {
    pub fn load_from_lyr_frm<P:AsRef<Path>>(lyr:P,frm:P) -> Result<Subtitles,String> {
        let frm : &Path = frm.as_ref();
        let lyr : &Path = lyr.as_ref();
        let mut subtitles = Subtitles::default();
        let lyr_file = try!(File::open(lyr).map_err(|e| e.description().to_string() ));
        let frm_file = try!(File::open(frm).map_err(|e| e.description().to_string() ));
        let lyr_file = BufReader::new(&lyr_file);
        let frm_file = BufReader::new(&frm_file);
        let mut current_sentence_options : SentenceOptions = SentenceOptions::default();
        for (line_number,lyr_line) in lyr_file.lines().enumerate() {
            let lyr_line = try!(
                lyr_line.map_err(|e|
                    format!("IoError when reading {} at line {} : '{}'",
                            lyr.display(),
                            line_number,
                            e.description())
                )
            );
            if (!lyr_line.starts_with("%") && !lyr_line.is_empty()) {
                let mut syllables : Vec<_> = lyr_line.split('&')
                                                     .map(|s|
                                                     Syllable {
                                                         text:s.to_string(),
                                                         begin:0,
                                                         end:0,
                                                         syllable_options:None,
                                                     })
                                                     .collect::<Vec<_>>();
                if (lyr_line.starts_with("&")) {
                    syllables.remove(0);
                };
                let sentence = Sentence {
                    syllables : syllables,
                    position : Position::Row(0),
                    sentence_options : Some(current_sentence_options)
                };
                subtitles.sentences.push(sentence);
            } else if lyr_line.starts_with("%color") {
                use utils::parse_bgr;
                let colors : Vec<_> = lyr_line.split_whitespace().collect();
                if colors.len() == 4 {
                    let alive_color = parse_bgr(colors[1]);
                    let transition_color = parse_bgr(colors[2]);
                    let dead_color = parse_bgr(colors[3]);
                    match (alive_color,transition_color,dead_color) {
                        (Ok(alive_color),Ok(transition_color),Ok(dead_color)) => {
                            if current_sentence_options.syllable_options.is_none() {
                                current_sentence_options.syllable_options = Some(SyllableOptions::default());
                            }
                            current_sentence_options.syllable_options.as_mut().unwrap().alive_color = Some(alive_color);
                            current_sentence_options.syllable_options.as_mut().unwrap().transition_color = Some(transition_color);
                            current_sentence_options.syllable_options.as_mut().unwrap().dead_color = Some(dead_color);
                        },
                        _ => {
                            error!("Invalid %color syntax when reading {} at line {} : '{}'",lyr.display(),line_number,lyr_line);
                        }
                    }
                } else {
                    error!("Invalid %color syntax when reading {} at line {} : '{}'",lyr.display(),line_number,lyr_line);
                }
            };
        }
        let mut frames : Vec<(u32,u32)> = vec!();
        for (line_number,frm_line) in frm_file.lines().enumerate() {
            let frm_line = try!(
                frm_line.map_err(|e|
                    format!("IoError when reading {} at line {} : '{}'",
                            frm.display(),
                            line_number,
                            e.description())
                )
            );
            if !frm_line.trim().is_empty() {
                let line_frames : Result<Vec<_>,_> = frm_line.split(' ')
                                                     .map(|s| s.parse::<u32>())
                                                     .collect();
                let begin_end = line_frames.map_err(|e| {
                    format!("{}",e)
                }).and_then(|line_frames| {
                    match (line_frames.get(0),line_frames.get(1),line_frames.get(2)) {
                        (Some(&begin),Some(&end),None) => {
                            Ok((begin,end))
                        },
                        (None,_,_) | (_,None,_) => {
                            Err(format!("Error while parsing frm file '{}' at line {}, not enough values",frm.display(),line_number))
                        },
                        (_,_,Some(_)) => {
                            Err(format!("Error while parsing frm file '{}' at line {}, too many values",frm.display(),line_number))
                        }
                    }
                });
                let begin_end = try!(begin_end);
                frames.push(begin_end);
            } else {
                warn!("empty line {} in frm file '{}'",line_number,frm.display());
            }
        };
        let mut frame_iter = frames.iter();
        'sentences: for sentence in subtitles.sentences.iter_mut() {
            for syllable in sentence.syllables.iter_mut() {
                match frame_iter.next() {
                    Some(&(begin,end)) => {
                        syllable.begin = begin ;
                        syllable.end = end ;
                    },
                    None => {
                        break 'sentences;
                    }
                }
            }
        };
        let default_sentence_options : SentenceOptions =
            subtitles.subtitles_options.as_ref().map(
                |ref sub_opts| sub_opts.sentence_options.unwrap_or(SentenceOptions::default())
            ).unwrap_or(SentenceOptions::default());
        for i in 0..subtitles.sentences.len() {
            let (first_half,mut last_half) = subtitles.sentences.split_at_mut(i);
            let sentence = last_half.first_mut().expect("Unexpected None for subtitles last_half");
            set_best_sentence_row(first_half,sentence,default_sentence_options);
        }
        Ok(subtitles)
    }

    /// Note that it will use the render_target used by the renderer,
    /// meaning that it can be a texture or the window depending on what
    /// is used with Displayer
    fn print_subtitle_frame_at(&self,displayer:&mut Displayer,frame_number:u32) -> Result<(),String> {
        let frame = ::display::frame::Frame::from_subtitles(self, frame_number);
        frame.draw(displayer);
        Ok(())
    }

    pub fn get_texture_at_frame(&self,displayer:&mut Displayer,frame:u32) -> Result<Texture,String> {
        use sdl2::pixels::Color;
        use sdl2::pixels::PixelFormatEnum::ARGB8888;
        fn ceil_power_of_2(v:f64) -> u32 {
            2u32.pow(v.log2().ceil() as u32)
        };
        let (renderer_w,renderer_h) = try!(displayer.sdl_renderer().output_size());
        let texture_width = ceil_power_of_2(renderer_w as f64);
        let texture_height = ceil_power_of_2(renderer_h as f64);
        let mut texture = displayer.sdl_renderer().create_texture_target(ARGB8888,texture_width,texture_height)
            .expect("Failed to create texture");
        texture.set_blend_mode(::sdl2::render::BlendMode::Blend);
        if let Some(ref mut render_target) = displayer.sdl_renderer_mut().render_target() {
            let old_texture = render_target.set(texture).expect("Failed to set texture as target");
            debug_assert!(old_texture.is_none());
        } else {
            error!("Render target are not supported with this GC driver");
            return Err("Render target are not supported with this GC driver".to_string());
        };
        let res = {
            displayer.sdl_renderer_mut().set_viewport(Some(Rect::new(0,0,renderer_w,renderer_h)));
            displayer.sdl_renderer_mut().set_draw_color(Color::RGBA(0,0,0,0));
            // make the texture transparent
            displayer.sdl_renderer_mut().clear();
            // draw subtitles on current render target
            self.print_subtitle_frame_at(displayer,frame)
        };
        displayer.sdl_renderer_mut().set_viewport(None);
        let new_texture = {
            if let Some(ref mut render_target) = displayer.sdl_renderer_mut().render_target() {
                render_target.reset()
                    .expect("Failed to reset render_target")
                    .expect("Failed to retrive texture from renderer")
            } else {
                error!("An unknown error happened; Failed to get render_target from renderer");
                panic!("Failed to get render_target from renderer")
            }
        };
        res.and(Ok(new_texture))
    }
}
<|endoftext|>


<commit_before>use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::symbols::Symbols;
use syntax::ast::expr::*;

pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indentation: usize,
    run_codegen: bool,
    ast_root: ExprWrapper
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        let expr = Box::new(Expr::BlockExpr(Vec::new()));
        let wrapper = ExprWrapper::new(expr, 0, 0, 0, 0);

        Parser {
            lexer: tokenizer,
            indentation: 0,
            run_codegen: true,
            ast_root: wrapper
        }
    }

    // Get the next token from the lexer
    fn next_token(&mut self) -> Token {
        self.lexer.get_tok()
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&mut self, msg: &str) {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        self.run_codegen = false;

        println!("Error on line: {} col: {}, {}", start_line, start_column, msg);

        // Skip to the end of the line (at Indent token) and allow parsing to continue
        loop {
            // Note: This consumes the Indent token, which probably isnt ideal.
            match self.next_token() {
                Indent(_) => break,
                EOF => break,
                _ => ()
            }
        }
    }

    fn expect_error(&mut self, reason: &str, expect: &str, got: &str) {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got));
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&mut self, depth: usize) -> Option<ExprWrapper> {
        if self.indentation == depth {
            return None;
        }

        self.write_error("Incorrect indentation level");

        None
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_declaration(&mut self) -> Option<ExprWrapper> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();

                match token1 {
                    // Symbol(punc) => {
                    //     match punc {
                    //         symbols::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Symbol here"))
                    //     }
                    // }
                    Symbol(Symbols::Equals) => {
                        return self.parse_expression();
                    },
                    _ => self.write_error("Invalid sequence")
                }
            },
            Error(msg) => self.write_error(&msg),
            _ => self.expect_error("", "a variable name", "something else")
        }

        None
    }

    fn expect_token(&mut self, token: &Token, nextToken: Token) -> bool {
        if token == token {
            return true;
        }
        self.expect_error("", "", "");
        return false;
    }

    fn collect_args(&mut self) -> Option<Vec<ExprWrapper>> {
        let mut args = Vec::new();
        let tok = self.next_token();
        let mut seen_one_arg = false;
        println!("Before While");
        while true {
            if self.expect_token(&tok, Symbol(Symbols::ParenClose)) {
                println!("hit the close paren {:?}, which is {:?}", tok, Symbol(Symbols::ParenClose));
                return Some(args);
            }
            println!("passed the close paren");

            let name = match tok {
                Token::Identifier(ref name) => Some(name),
                _ => {
                    self.write_error(&format!("Unsupported keyword {:?}.", tok));
                    None
                }
            };
            if let Some(arg) = name {
                println!("hit the ident: {}", arg);
                args.push(ExprWrapper::new_default(
                    Box::new(Expr::IdentExpr(String::from_str(arg)))));
                let tok = self.next_token();
                if self.expect_token(&tok, Symbol(Symbols::Comma)) {
                    println!("hit the comma!");
                    if !seen_one_arg {
                        self.write_error(&format!("Invalid syntax."));
                        return None;
                    }
                    continue;
                }
            } else {
                return None;
            }
            let tok = self.next_token();
        }
        None
    }

    // Parses a print function/statement
    fn parse_print_fn(&mut self) -> Option<ExprWrapper> {
        let tok = self.next_token();
        if !self.expect_token(&tok, Symbol(Symbols::ParenOpen)) {
            return None;
        }

        println!("Before Collect");
        let args = self.collect_args();
        return None;
        // Return the ast of the print function
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Option<ExprWrapper> {
        match keyword {
//            Keywords::Def => {
//                self.parse_declaration()
//            },
            Keywords::Print => {
                self.parse_print_fn()
            },
            _ => {
                self.write_error(&format!("Unsupported keyword {:?}.", keyword));
                None
            }
        }
    }

    #[allow(dead_code)]
    fn parse_expression(&self) -> Option<ExprWrapper> {
        None
    }

    // Parse numbers into their correct representation
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Option<ExprWrapper> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        None
    }

    // Parse the file
    #[allow(unused_variables)]
    pub fn parse(&mut self) {
        self.start();

        // Generate AST
        loop {
            // Parse the token into the next node of the AST
            let token = self.next_token();

            // Debug:
            println!("{:?}", token);

            match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
//                    self.parse_expression()
                    panic!("Unimplemented top level token 'Identifier'");
                },
                Indent(depth) => {
                    // ToDo: Keep track of indentation level when preceeding a statement
                    // Might need look ahead to see if next token is Comment or Indent
                    // which means you didn't actually dedent.
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    if let Some(exprwrapper) = self.handle_keywords(keyword) {
                        if let &mut Expr::BlockExpr(ref mut vec) = self.ast_root.get_expr() {
                            vec.push(exprwrapper);
                        }
                    }
                },
                Symbol(punc) => {
                    panic!("Unimplemented top level token 'Symbol'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                },
                Error(err) => {
                    self.write_error(&err);
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => break
            };
        }

        // Do semantic analysis on AST

        // Run codegen when no errors have been found
        if self.run_codegen {
            self.ast_root.gen_code();
        }
    }
}
<commit_msg>Unbroke the token_expect fn<commit_after>use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::symbols::Symbols;
use syntax::ast::expr::*;

pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indentation: usize,
    run_codegen: bool,
    ast_root: ExprWrapper
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        let expr = Box::new(Expr::BlockExpr(Vec::new()));
        let wrapper = ExprWrapper::new(expr, 0, 0, 0, 0);

        Parser {
            lexer: tokenizer,
            indentation: 0,
            run_codegen: true,
            ast_root: wrapper
        }
    }

    // Get the next token from the lexer
    fn next_token(&mut self) -> Token {
        self.lexer.get_tok()
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&mut self, msg: &str) {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        self.run_codegen = false;

        println!("Error on line: {} col: {}, {}", start_line, start_column, msg);

        // Skip to the end of the line (at Indent token) and allow parsing to continue
        loop {
            // Note: This consumes the Indent token, which probably isnt ideal.
            match self.next_token() {
                Indent(_) => break,
                EOF => break,
                _ => ()
            }
        }
    }

    fn expect_error(&mut self, reason: &str, expect: &str, got: &str) {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got));
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&mut self, depth: usize) -> Option<ExprWrapper> {
        if self.indentation == depth {
            return None;
        }

        self.write_error("Incorrect indentation level");

        None
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_declaration(&mut self) -> Option<ExprWrapper> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();

                match token1 {
                    // Symbol(punc) => {
                    //     match punc {
                    //         symbols::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Symbol here"))
                    //     }
                    // }
                    Symbol(Symbols::Equals) => {
                        return self.parse_expression();
                    },
                    _ => self.write_error("Invalid sequence")
                }
            },
            Error(msg) => self.write_error(&msg),
            _ => self.expect_error("", "a variable name", "something else")
        }

        None
    }

    fn expect_token(&self, token: &Token, next_token: Token) -> bool {
        if *token == next_token {
            return true;
        }
        return false;
    }

    fn collect_args(&mut self) -> Option<Vec<ExprWrapper>> {
        let mut args = Vec::new();
        let mut seen_one_arg = false;
        println!("Before While");
        loop {
            let tok = self.next_token();
            if self.expect_token(&tok, Symbol(Symbols::ParenClose)) {
                println!("hit the close paren {:?}, which is {:?}", tok, Symbol(Symbols::ParenClose));
                return Some(args);
            }
            println!("passed the close paren");

            let name = match tok {
                Token::Identifier(ref name) => Some(name),
                _ => {
                    self.write_error(&format!("Unsupported keyword {:?}.", tok));
                    None
                }
            };
            if let Some(arg) = name {
                println!("hit the ident: {}", arg);
                args.push(ExprWrapper::new_default(
                    Box::new(Expr::IdentExpr(String::from_str(arg)))));
                let tok = self.next_token();
                if self.expect_token(&tok, Symbol(Symbols::Comma)) {
                    println!("hit the comma!");
                    if !seen_one_arg {
                        self.write_error(&format!("Invalid syntax."));
                        return None;
                    }
                    seen_one_arg = true;
                    continue;
                }
            } else {
                return None;
            }
        }
    }

    // Parses a print function/statement
    fn parse_print_fn(&mut self) -> Option<ExprWrapper> {
        let tok = self.next_token();
        if !self.expect_token(&tok, Symbol(Symbols::ParenOpen)) {
            return None;
        }

        println!("Before Collect");
        // let args = self.collect_args();
        self.collect_args();
        return None;
        // Return the ast of the print function
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Option<ExprWrapper> {
        match keyword {
//            Keywords::Def => {
//                self.parse_declaration()
//            },
            Keywords::Print => {
                self.parse_print_fn()
            },
            _ => {
                self.write_error(&format!("Unsupported keyword {:?}.", keyword));
                None
            }
        }
    }

    #[allow(dead_code)]
    fn parse_expression(&self) -> Option<ExprWrapper> {
        None
    }

    // Parse numbers into their correct representation
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Option<ExprWrapper> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        None
    }

    // Parse the file
    #[allow(unused_variables)]
    pub fn parse(&mut self) {
        self.start();

        // Generate AST
        loop {
            // Parse the token into the next node of the AST
            let token = self.next_token();

            // Debug:
            println!("{:?}", token);

            match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
//                    self.parse_expression()
                    panic!("Unimplemented top level token 'Identifier'");
                },
                Indent(depth) => {
                    // ToDo: Keep track of indentation level when preceeding a statement
                    // Might need look ahead to see if next token is Comment or Indent
                    // which means you didn't actually dedent.
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    if let Some(exprwrapper) = self.handle_keywords(keyword) {
                        if let &mut Expr::BlockExpr(ref mut vec) = self.ast_root.get_expr() {
                            vec.push(exprwrapper);
                        }
                    }
                },
                Symbol(punc) => {
                    panic!("Unimplemented top level token 'Symbol'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                },
                Error(err) => {
                    self.write_error(&err);
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => break
            };
        }

        // Do semantic analysis on AST

        // Run codegen when no errors have been found
        if self.run_codegen {
            self.ast_root.gen_code();
        }
    }
}
<|endoftext|>


<commit_before>pub mod ffi;

use std::mem;
use std::ptr;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind};

use super::utils::fn_ptr::FnPtrLoader;

#[inline]
pub fn load<T: FnPtrLoader>(loader: &T) {
   unsafe {
      ffi::load_functions(loader)
   };
}

#[inline]
fn gl_error<T>(message: &str) -> Result<T, RuntimeError> {
   Err(
      RuntimeError::new(
         ErrorKind::GL,
         message.to_string()
      )
   )
}

#[inline]
fn gl_result<T>(value: T) -> Result<T, RuntimeError> {
   let result = unsafe {
      ffi::glGetError()
   };

   match result {
      ffi::GL_NO_ERROR => Ok(value),
      ffi::GL_INVALID_ENUM => gl_error(
         "An unacceptable value is specified for an enumerated argument"
      ),
      ffi::GL_INVALID_VALUE => gl_error(
         "A numeric argument is out of range"
      ),
      ffi::GL_INVALID_OPERATION => gl_error(
         "The specified operation is not allowed in the current state"
      ),
      ffi::GL_INVALID_FRAMEBUFFER_OPERATION => gl_error(
         "The framebuffer object is not complete"
      ),
      ffi::GL_OUT_OF_MEMORY => gl_error(
         "There is not enough memory left to execute the command"
      ),
      ffi::GL_STACK_UNDERFLOW => gl_error(
         "Performing an operation that would cause an internal stack to underflow"
      ),
      ffi::GL_STACK_OVERFLOW => gl_error(
         "Performing an operation that would cause an internal stack to overflow"
      ),
      _ => gl_error("Unknown OpenGL error")
   }
}

#[inline]
pub fn reset_pixelstore_alignment() -> Result<(), RuntimeError> {
   unsafe {
      ffi::glPixelStorei(ffi::GL_UNPACK_ALIGNMENT, 1);
   }

   gl_result(())
}

#[inline]
pub fn enable_framebuffer_srgb() -> Result<(), RuntimeError> {
   unsafe {
      ffi::glEnable(ffi::GL_FRAMEBUFFER_SRGB);
   }

   gl_result(())
}

pub struct Texture {
   pub name: ffi::GLuint,
}

impl Texture {
   pub fn new(width: u32, height: u32) -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenTextures(1, &mut name);

         ffi::glBindTexture(ffi::GL_TEXTURE_2D, name);

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_S,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_T,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MIN_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MAG_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(Texture {
         name: name,
      })
   }

   #[inline]
   pub fn bind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindTexture(ffi::GL_TEXTURE_2D, self.name);
      }

      gl_result(())
   }

   #[inline]
   pub fn resize(&self, width: u32, height: u32) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(())
   }

   #[inline]
   pub fn update(&self, width: u32, height: u32) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glTexSubImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            0, 0, width as ffi::GLsizei, height as ffi::GLsizei,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(())
   }
}

impl Drop for Texture {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteTextures(1, &self.name)
      };
   }
}

pub struct Framebuffer {
   pub name: ffi::GLuint,
}

impl Framebuffer {
   pub fn new(texture: &Texture) -> Result<Self, RuntimeError> {
      let name = try!(Framebuffer::get_framebuffers());

      let framebuffer = Framebuffer {
         name: name,
      };

      try!(framebuffer.bind());
      try!(framebuffer.attach_texture(texture));
      try!(framebuffer.unbind());

      Ok(framebuffer)
   }

   #[inline]
   pub fn get_framebuffers() -> Result<ffi::GLuint, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenFramebuffers(1, &mut name)
      };

      gl_result(name)
   }

   #[inline]
   pub fn bind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn unbind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, 0)
      };

      gl_result(())
   }

   #[inline]
   pub fn attach_texture(&self, texture: &Texture) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glFramebufferTexture2D(
            ffi::GL_READ_FRAMEBUFFER,
            ffi::GL_COLOR_ATTACHMENT0,
            ffi::GL_TEXTURE_2D,
            texture.name,
            0
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn blit(&self, width: u32, height: u32) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBlitFramebuffer(
            0, 0, width as ffi::GLint, height as ffi::GLint,
            0, 0, width as ffi::GLint, height as ffi::GLint,
            ffi::GL_COLOR_BUFFER_BIT,
            ffi::GL_NEAREST
         )
      };

      gl_result(())
   }
}

impl Drop for Framebuffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteFramebuffers(1, &self.name)
      };
   }
}

pub struct Buffer {
   pub name: ffi::GLuint,
   pub ptr: *mut ffi::c_void,
   pub size: ffi::GLsizeiptr,
}

impl Buffer {
   pub fn new() -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenBuffers(1, &mut name)
      };

      gl_result(Buffer {
         name: name,
         ptr: ptr::null_mut(),
         size: 0,
      })
   }

   #[inline]
   pub fn bind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn unbind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, 0)
      };

      gl_result(())
   }

   #[inline]
   pub fn init_data(&mut self, size: usize) -> Result<(), RuntimeError> {
      self.size = size as ffi::GLsizeiptr;
      unsafe {
         ffi::glBufferData(
            ffi::GL_PIXEL_UNPACK_BUFFER,
            self.size,
            ptr::null(),
            ffi::GL_STREAM_DRAW
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn map(&mut self) -> Result<(), RuntimeError> {
      self.ptr = unsafe {
         ffi::glMapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, ffi::GL_WRITE_ONLY)
      };

      gl_result(())
   }

   #[inline]
   pub fn map_range(&mut self) -> Result<(), RuntimeError> {
      self.ptr = unsafe {
         ffi::glMapBufferRange(
            ffi::GL_PIXEL_UNPACK_BUFFER, 0, self.size,
            ffi::GL_MAP_WRITE_BIT// | ffi::GL_MAP_UNSYNCHRONIZED_BIT
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn unmap(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glUnmapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER)
      };

      gl_result(())
   }
}

impl Drop for Buffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteBuffers(1, &self.name)
      };
   }
}

pub struct Shader {
   pub name: ffi::GLuint,
}

impl Shader {
   pub fn new(shader_type: ffi::GLenum) -> Self {
      let name = unsafe {
         ffi::glCreateShader(shader_type)
      };

      Shader {
         name: name,
      }
   }

   #[inline]
   pub fn shader_source(&self, string: &str) {
      let cstring = CString::new(string).unwrap().as_ptr();

      unsafe {
         ffi::glShaderSource(self.name, 1, &cstring, ptr::null())
      };
   }

   #[inline]
   pub fn compile(&self) {
      unsafe {
         ffi::glCompileShader(self.name)
      };
   }

   #[inline]
   pub fn is_compiled(&self) -> bool {
      let mut compiled: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetShaderiv(self.name, ffi::GL_COMPILE_STATUS, &mut compiled);
      };

      compiled == 1
   }
}

impl Drop for Shader {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteShader(self.name)
      };
   }
}

pub struct Program {
   pub name: ffi::GLuint,
}

impl Program {
   pub fn new() -> Self {
      let name = unsafe {
         ffi::glCreateProgram()
      };

      Program {
         name: name,
      }
   }

   #[inline]
   pub fn attach_shader(&self, shader: &Shader) {
      unsafe {
         ffi::glAttachShader(self.name, shader.name)
      };
   }

   #[inline]
   pub fn link(&self) {
      unsafe {
         ffi::glLinkProgram(self.name)
      };
   }

   #[inline]
   pub fn use_(&self) {
      unsafe {
         ffi::glUseProgram(self.name)
      };
   }

   #[inline]
   pub fn is_linked(&self) -> bool {
      let mut linked: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetProgramiv(self.name, ffi::GL_LINK_STATUS, &mut linked);
      };

      linked == 1
   }
}

impl Drop for Program {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteProgram(self.name)
      };
   }
}
<commit_msg>Error checking for the GL Shader and Program wrappers<commit_after>pub mod ffi;

use std::mem;
use std::ptr;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind};

use super::utils::fn_ptr::FnPtrLoader;

#[inline]
pub fn load<T: FnPtrLoader>(loader: &T) {
   unsafe {
      ffi::load_functions(loader)
   };
}

#[inline]
fn gl_error<T>(message: &str) -> Result<T, RuntimeError> {
   Err(
      RuntimeError::new(
         ErrorKind::GL,
         message.to_string()
      )
   )
}

#[inline]
fn gl_result<T>(value: T) -> Result<T, RuntimeError> {
   let result = unsafe {
      ffi::glGetError()
   };

   match result {
      ffi::GL_NO_ERROR => Ok(value),
      ffi::GL_INVALID_ENUM => gl_error(
         "An unacceptable value is specified for an enumerated argument"
      ),
      ffi::GL_INVALID_VALUE => gl_error(
         "A numeric argument is out of range"
      ),
      ffi::GL_INVALID_OPERATION => gl_error(
         "The specified operation is not allowed in the current state"
      ),
      ffi::GL_INVALID_FRAMEBUFFER_OPERATION => gl_error(
         "The framebuffer object is not complete"
      ),
      ffi::GL_OUT_OF_MEMORY => gl_error(
         "There is not enough memory left to execute the command"
      ),
      ffi::GL_STACK_UNDERFLOW => gl_error(
         "Performing an operation that would cause an internal stack to underflow"
      ),
      ffi::GL_STACK_OVERFLOW => gl_error(
         "Performing an operation that would cause an internal stack to overflow"
      ),
      _ => gl_error("Unknown OpenGL error")
   }
}

#[inline]
pub fn reset_pixelstore_alignment() -> Result<(), RuntimeError> {
   unsafe {
      ffi::glPixelStorei(ffi::GL_UNPACK_ALIGNMENT, 1);
   }

   gl_result(())
}

#[inline]
pub fn enable_framebuffer_srgb() -> Result<(), RuntimeError> {
   unsafe {
      ffi::glEnable(ffi::GL_FRAMEBUFFER_SRGB);
   }

   gl_result(())
}

pub struct Texture {
   pub name: ffi::GLuint,
}

impl Texture {
   pub fn new(width: u32, height: u32) -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenTextures(1, &mut name);

         ffi::glBindTexture(ffi::GL_TEXTURE_2D, name);

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_S,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_T,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MIN_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MAG_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(Texture {
         name: name,
      })
   }

   #[inline]
   pub fn bind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindTexture(ffi::GL_TEXTURE_2D, self.name);
      }

      gl_result(())
   }

   #[inline]
   pub fn resize(&self, width: u32, height: u32) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(())
   }

   #[inline]
   pub fn update(&self, width: u32, height: u32) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glTexSubImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            0, 0, width as ffi::GLsizei, height as ffi::GLsizei,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(())
   }
}

impl Drop for Texture {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteTextures(1, &self.name)
      };
   }
}

pub struct Framebuffer {
   pub name: ffi::GLuint,
}

impl Framebuffer {
   pub fn new(texture: &Texture) -> Result<Self, RuntimeError> {
      let name = try!(Framebuffer::get_framebuffers());

      let framebuffer = Framebuffer {
         name: name,
      };

      try!(framebuffer.bind());
      try!(framebuffer.attach_texture(texture));
      try!(framebuffer.unbind());

      Ok(framebuffer)
   }

   #[inline]
   pub fn get_framebuffers() -> Result<ffi::GLuint, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenFramebuffers(1, &mut name)
      };

      gl_result(name)
   }

   #[inline]
   pub fn bind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn unbind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, 0)
      };

      gl_result(())
   }

   #[inline]
   pub fn attach_texture(&self, texture: &Texture) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glFramebufferTexture2D(
            ffi::GL_READ_FRAMEBUFFER,
            ffi::GL_COLOR_ATTACHMENT0,
            ffi::GL_TEXTURE_2D,
            texture.name,
            0
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn blit(&self, width: u32, height: u32) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBlitFramebuffer(
            0, 0, width as ffi::GLint, height as ffi::GLint,
            0, 0, width as ffi::GLint, height as ffi::GLint,
            ffi::GL_COLOR_BUFFER_BIT,
            ffi::GL_NEAREST
         )
      };

      gl_result(())
   }
}

impl Drop for Framebuffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteFramebuffers(1, &self.name)
      };
   }
}

pub struct Buffer {
   pub name: ffi::GLuint,
   pub ptr: *mut ffi::c_void,
   pub size: ffi::GLsizeiptr,
}

impl Buffer {
   pub fn new() -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenBuffers(1, &mut name)
      };

      gl_result(Buffer {
         name: name,
         ptr: ptr::null_mut(),
         size: 0,
      })
   }

   #[inline]
   pub fn bind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn unbind(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, 0)
      };

      gl_result(())
   }

   #[inline]
   pub fn init_data(&mut self, size: usize) -> Result<(), RuntimeError> {
      self.size = size as ffi::GLsizeiptr;
      unsafe {
         ffi::glBufferData(
            ffi::GL_PIXEL_UNPACK_BUFFER,
            self.size,
            ptr::null(),
            ffi::GL_STREAM_DRAW
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn map(&mut self) -> Result<(), RuntimeError> {
      self.ptr = unsafe {
         ffi::glMapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, ffi::GL_WRITE_ONLY)
      };

      gl_result(())
   }

   #[inline]
   pub fn map_range(&mut self) -> Result<(), RuntimeError> {
      self.ptr = unsafe {
         ffi::glMapBufferRange(
            ffi::GL_PIXEL_UNPACK_BUFFER, 0, self.size,
            ffi::GL_MAP_WRITE_BIT// | ffi::GL_MAP_UNSYNCHRONIZED_BIT
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn unmap(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glUnmapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER)
      };

      gl_result(())
   }
}

impl Drop for Buffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteBuffers(1, &self.name)
      };
   }
}

pub struct Shader {
   pub name: ffi::GLuint,
}

impl Shader {
   pub fn new(shader_type: ffi::GLenum) -> Result<Self, RuntimeError> {
      let name = unsafe {
         ffi::glCreateShader(shader_type)
      };

      gl_result(Shader {
         name: name,
      })
   }

   #[inline]
   pub fn shader_source(&self, string: &str) -> Result<(), RuntimeError> {
      let cstring = CString::new(string).unwrap().as_ptr();

      unsafe {
         ffi::glShaderSource(self.name, 1, &cstring, ptr::null())
      };

      gl_result(())
   }

   #[inline]
   pub fn compile(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glCompileShader(self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn is_compiled(&self) -> Result<bool, RuntimeError> {
      let mut compiled: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetShaderiv(self.name, ffi::GL_COMPILE_STATUS, &mut compiled);
      };

      gl_result(compiled == 1)
   }
}

impl Drop for Shader {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteShader(self.name)
      };
   }
}

pub struct Program {
   pub name: ffi::GLuint,
}

impl Program {
   pub fn new() -> Result<Self, RuntimeError> {
      let name = unsafe {
         ffi::glCreateProgram()
      };

      gl_result(Program {
         name: name,
      })
   }

   #[inline]
   pub fn attach_shader(&self, shader: &Shader) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glAttachShader(self.name, shader.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn link(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glLinkProgram(self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn use_(&self) -> Result<(), RuntimeError> {
      unsafe {
         ffi::glUseProgram(self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn is_linked(&self) -> Result<bool, RuntimeError> {
      let mut linked: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetProgramiv(self.name, ffi::GL_LINK_STATUS, &mut linked);
      };

      gl_result(linked == 1)
   }
}

impl Drop for Program {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteProgram(self.name)
      };
   }
}
<|endoftext|>


<commit_before>use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use BindServer;
use futures::stream::Stream;
use futures::future::{Then, Future};
use net2;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_service::{NewService, Service};

// TODO: Add more options, e.g.:
// - max concurrent requests
// - request timeout
// - read timeout
// - write timeout
// - max idle time
// - max lifetime

/// A builder for TCP servers.
///
/// Setting up a server needs, at minimum:
///
/// - A server protocol implementation
/// - An address
/// - A service to provide
///
/// In addition to those basics, the builder provides some additional
/// configuration, which is expected to grow over time.
///
/// See the crate docs for an example.
pub struct TcpServer<Kind, P> {
    _kind: PhantomData<Kind>,
    proto: Arc<P>,
    threads: usize,
    addr: SocketAddr,
}

impl<Kind, P> TcpServer<Kind, P> where
    P: BindServer<Kind, TcpStream> + Send + Sync + 'static
{
    /// Starts building a server for the given protocol and address, with
    /// default configuration.
    ///
    /// Generally, a protocol is implemented *not* by implementing the
    /// `BindServer` trait directly, but instead by implementing one of the
    /// protocol traits:
    ///
    /// - `pipeline::ServerProto`
    /// - `multiplex::ServerProto`
    /// - `streaming::pipeline::ServerProto`
    /// - `streaming::multiplex::ServerProto`
    ///
    /// See the crate documentation for more details on those traits.
    pub fn new(protocol: P, addr: SocketAddr) -> TcpServer<Kind, P> {
        TcpServer {
            _kind: PhantomData,
            proto: Arc::new(protocol),
            threads: 1,
            addr: addr,
        }
    }

    /// Set the address for the server.
    pub fn addr(&mut self, addr: SocketAddr) {
        self.addr = addr;
    }

    /// Set the number of threads running simultaneous event loops (Unix only).
    pub fn threads(&mut self, threads: usize) {
        assert!(threads > 0);
        if cfg!(unix) {
            self.threads = threads;
        }
    }

    /// Start up the server, providing the given service on it.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn serve<S>(&self, new_service: S) where
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let new_service = Arc::new(new_service);
        self.with_handle(move |_| new_service.clone())
    }

    /// Start up the server, providing the given service on it, and providing
    /// access to the event loop handle.
    ///
    /// The `new_service` argument is a closure that is given an event loop
    /// handle, and produces a value implementing `NewService`. That value is in
    /// turned used to make a new service instance for each incoming connection.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn with_handle<F, S>(&self, new_service: F) where
        F: Fn(&Handle) -> S + Send + Sync + 'static,
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let proto = self.proto.clone();
        let new_service = Arc::new(new_service);
        let addr = self.addr;
        let workers = self.threads;

        let threads = (0..self.threads - 1).map(|i| {
            let proto = proto.clone();
            let new_service = new_service.clone();

            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                serve(proto, addr, workers, &*new_service)
            }).unwrap()
        }).collect::<Vec<_>>();

        serve(proto, addr, workers, &*new_service);

        for thread in threads {
            thread.join().unwrap();
        }
    }
}

fn serve<P, Kind, F, S>(binder: Arc<P>, addr: SocketAddr, workers: usize, new_service: &F)
    where P: BindServer<Kind, TcpStream>,
          F: Fn(&Handle) -> S,
          S: NewService + Send + Sync,
          S::Instance: 'static,
          P::ServiceError: 'static,
          P::ServiceResponse: 'static,
          P::ServiceRequest: 'static,
          S::Request: From<P::ServiceRequest>,
          S::Response: Into<P::ServiceResponse>,
          S::Error: Into<P::ServiceError>,
{
    struct WrapService<S, Request, Response, Error> {
        inner: S,
        _marker: PhantomData<fn() -> (Request, Response, Error)>,
    }

    impl<S, Request, Response, Error> Service for WrapService<S, Request, Response, Error>
        where S: Service,
              S::Request: From<Request>,
              S::Response: Into<Response>,
              S::Error: Into<Error>,
    {
        type Request = Request;
        type Response = Response;
        type Error = Error;
        type Future = Then<S::Future,
                           Result<Response, Error>,
                           fn(Result<S::Response, S::Error>) -> Result<Response, Error>>;

        fn call(&self, req: Request) -> Self::Future {
            fn change_types<A, B, C, D>(r: Result<A, B>) -> Result<C, D>
                where A: Into<C>,
                      B: Into<D>,
            {
                match r {
                    Ok(e) => Ok(e.into()),
                    Err(e) => Err(e.into()),
                }
            }

            self.inner.call(S::Request::from(req)).then(change_types)
        }
    }

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let new_service = new_service(&handle);
    let listener = listener(&addr, workers, &handle).unwrap();

    let server = listener.incoming().for_each(move |(socket, _)| {
        // Create the service
        let service = try!(new_service.new_service());

        // Bind it!
        binder.bind_server(&handle, socket, WrapService {
            inner: service,
            _marker: PhantomData,
        });

        Ok(())
    });

    core.run(server).unwrap();
}

fn listener(addr: &SocketAddr,
            workers: usize,
            handle: &Handle) -> io::Result<TcpListener> {
    let listener = match *addr {
        SocketAddr::V4(_) => try!(net2::TcpBuilder::new_v4()),
        SocketAddr::V6(_) => try!(net2::TcpBuilder::new_v6()),
    };
    try!(configure_tcp(workers, &listener));
    try!(listener.reuse_address(true));
    try!(listener.bind(addr));
    listener.listen(1024).and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

#[cfg(unix)]
fn configure_tcp(workers: usize, tcp: &net2::TcpBuilder) -> io::Result<()> {
    use net2::unix::*;

    if workers > 1 {
        try!(tcp.reuse_port(true));
    }

    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_workers: usize, _tcp: &net2::TcpBuilder) -> io::Result<()> {
    Ok(())
}
<commit_msg>Revert "Generalize TcpServer::serve's service a bit"<commit_after>use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use BindServer;
use futures::stream::Stream;
use net2;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_service::NewService;

// TODO: Add more options, e.g.:
// - max concurrent requests
// - request timeout
// - read timeout
// - write timeout
// - max idle time
// - max lifetime

/// A builder for TCP servers.
///
/// Setting up a server needs, at minimum:
///
/// - A server protocol implementation
/// - An address
/// - A service to provide
///
/// In addition to those basics, the builder provides some additional
/// configuration, which is expected to grow over time.
///
/// See the crate docs for an example.
pub struct TcpServer<Kind, P> {
    _kind: PhantomData<Kind>,
    proto: Arc<P>,
    threads: usize,
    addr: SocketAddr,
}

impl<Kind, P> TcpServer<Kind, P> where
    P: BindServer<Kind, TcpStream> + Send + Sync + 'static
{
    /// Starts building a server for the given protocol and address, with
    /// default configuration.
    ///
    /// Generally, a protocol is implemented *not* by implementing the
    /// `BindServer` trait directly, but instead by implementing one of the
    /// protocol traits:
    ///
    /// - `pipeline::ServerProto`
    /// - `multiplex::ServerProto`
    /// - `streaming::pipeline::ServerProto`
    /// - `streaming::multiplex::ServerProto`
    ///
    /// See the crate documentation for more details on those traits.
    pub fn new(protocol: P, addr: SocketAddr) -> TcpServer<Kind, P> {
        TcpServer {
            _kind: PhantomData,
            proto: Arc::new(protocol),
            threads: 1,
            addr: addr,
        }
    }

    /// Set the address for the server.
    pub fn addr(&mut self, addr: SocketAddr) {
        self.addr = addr;
    }

    /// Set the number of threads running simultaneous event loops (Unix only).
    pub fn threads(&mut self, threads: usize) {
        assert!(threads > 0);
        if cfg!(unix) {
            self.threads = threads;
        }
    }

    /// Start up the server, providing the given service on it.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn serve<S>(&self, new_service: S) where
        S: NewService<Request = P::ServiceRequest,
                      Response = P::ServiceResponse,
                      Error = P::ServiceError> + Send + Sync + 'static,
    {
        let new_service = Arc::new(new_service);
        self.with_handle(move |_| new_service.clone())
    }

    /// Start up the server, providing the given service on it, and providing
    /// access to the event loop handle.
    ///
    /// The `new_service` argument is a closure that is given an event loop
    /// handle, and produces a value implementing `NewService`. That value is in
    /// turned used to make a new service instance for each incoming connection.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn with_handle<F, S>(&self, new_service: F) where
        F: Fn(&Handle) -> S + Send + Sync + 'static,
        S: NewService<Request = P::ServiceRequest,
                      Response = P::ServiceResponse,
                      Error = P::ServiceError> + Send + Sync + 'static,
    {
        let proto = self.proto.clone();
        let new_service = Arc::new(new_service);
        let addr = self.addr;
        let workers = self.threads;

        let threads = (0..self.threads - 1).map(|i| {
            let proto = proto.clone();
            let new_service = new_service.clone();

            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                serve(proto, addr, workers, &*new_service)
            }).unwrap()
        }).collect::<Vec<_>>();

        serve(proto, addr, workers, &*new_service);

        for thread in threads {
            thread.join().unwrap();
        }
    }
}

fn serve<P, Kind, F, S>(binder: Arc<P>, addr: SocketAddr, workers: usize, new_service: &F)
    where P: BindServer<Kind, TcpStream>,
          F: Fn(&Handle) -> S,
          S: NewService<Request = P::ServiceRequest,
                        Response = P::ServiceResponse,
                        Error = P::ServiceError> + 'static,
{
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let new_service = new_service(&handle);
    let listener = listener(&addr, workers, &handle).unwrap();

    let server = listener.incoming().for_each(move |(socket, _)| {
        // Create the service
        let service = try!(new_service.new_service());

        // Bind it!
        binder.bind_server(&handle, socket, service);

        Ok(())
    });

    core.run(server).unwrap();
}

fn listener(addr: &SocketAddr,
            workers: usize,
            handle: &Handle) -> io::Result<TcpListener> {
    let listener = match *addr {
        SocketAddr::V4(_) => try!(net2::TcpBuilder::new_v4()),
        SocketAddr::V6(_) => try!(net2::TcpBuilder::new_v6()),
    };
    try!(configure_tcp(workers, &listener));
    try!(listener.reuse_address(true));
    try!(listener.bind(addr));
    listener.listen(1024).and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

#[cfg(unix)]
fn configure_tcp(workers: usize, tcp: &net2::TcpBuilder) -> io::Result<()> {
    use net2::unix::*;

    if workers > 1 {
        try!(tcp.reuse_port(true));
    }

    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_workers: usize, _tcp: &net2::TcpBuilder) -> io::Result<()> {
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::BTreeMap;

use handlebars::{Handlebars, Helper, HelperDef, Renderable, RenderContext, RenderError};
use serde_json::Value as Json;

use super::super::RenderResult;
use super::{to_json, JsonTruthy};

#[derive(Clone, Copy)]
pub struct EachAliveHelper;

impl HelperDef for EachAliveHelper {
    fn call(&self, h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> RenderResult<()> {
        let value = h.param(0).ok_or_else(|| {
            RenderError::new("Param not found for helper \"eachAlive\"")
        })?;
        if let Some(template) = h.template() {
            rc.promote_local_vars();
            let local_path_root = value.path_root().map(
                |p| format!("{}/{}", rc.get_path(), p),
            );
            let rendered = match (value.value().is_truthy(), value.value()) {
                (true, &Json::Array(ref list)) => {
                    let len = list.len();
                    for i in 0..len {
                        let member = list[i].as_object().ok_or_else(|| {
                            RenderError::new(format!(
                                "Param value is not a valid census \
                                member. Parameter content is: {:?}",
                                list[i]
                            ))
                        })?;
                        if member.contains_key("alive") && member["alive"].as_bool().unwrap() {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(), to_json(&(i == 0usize)));
                            local_rc.set_local_var("@last".to_string(), to_json(&(i == len - 1)));
                            local_rc.set_local_var("@index".to_string(), to_json(&i));

                            if let Some(block_param) = h.block_param() {
                                let mut map = BTreeMap::new();
                                map.insert(block_param.to_string(), to_json(&list[i]));
                                local_rc.push_block_context(&map);
                            }

                            template.render(r, &mut local_rc)?;

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }
                    }
                    Ok(())
                }
                (true, &Json::Object(ref obj)) => {
                    let mut first: bool = true;
                    if !obj.contains_key("alive") || !obj["alive"].as_bool().unwrap() {
                        return Ok(());
                    }
                    for k in obj.keys() {
                        let mut local_rc = rc.derive();
                        if let Some(ref p) = local_path_root {
                            local_rc.push_local_path_root(p.clone());
                        }
                        local_rc.set_local_var("@first".to_string(), to_json(&first));
                        local_rc.set_local_var("@key".to_string(), to_json(k));

                        if first {
                            first = false;
                        }

                        if let Some(inner_path) = value.path() {
                            let new_path =
                                format!("{}/{}.[{}]", local_rc.get_path(), inner_path, k);
                            local_rc.set_path(new_path);
                        }

                        if let Some((bp_key, bp_val)) = h.block_param_pair() {
                            let mut map = BTreeMap::new();
                            map.insert(bp_key.to_string(), to_json(k));
                            map.insert(bp_val.to_string(), to_json(obj.get(k).unwrap()));
                            local_rc.push_block_context(&map);
                        }

                        template.render(r, &mut local_rc)?;

                        if h.block_param().is_some() {
                            local_rc.pop_block_context();
                        }

                        if local_path_root.is_some() {
                            local_rc.pop_local_path_root();
                        }
                    }
                    Ok(())
                }
                (false, _) => {
                    if let Some(else_template) = h.inverse() {
                        else_template.render(r, rc)?;
                    }
                    Ok(())
                }
                _ => Err(RenderError::new(
                    format!("Param type is not iterable: {:?}", template),
                )),
            };

            rc.demote_local_vars();
            return rendered;
        }
        Ok(())
    }
}

pub static EACH_ALIVE: EachAliveHelper = EachAliveHelper;
<commit_msg>Fix populating @first and @last in eachAlive helper<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::BTreeMap;

use handlebars::{Handlebars, Helper, HelperDef, Renderable, RenderContext, RenderError};
use serde_json::Value as Json;

use super::super::RenderResult;
use super::{to_json, JsonTruthy};

#[derive(Clone, Copy)]
pub struct EachAliveHelper;

impl HelperDef for EachAliveHelper {
    fn call(&self, h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> RenderResult<()> {
        let value = h.param(0).ok_or_else(|| {
            RenderError::new("Param not found for helper \"eachAlive\"")
        })?;
        if let Some(template) = h.template() {
            rc.promote_local_vars();
            let local_path_root = value.path_root().map(
                |p| format!("{}/{}", rc.get_path(), p),
            );
            let rendered = match (value.value().is_truthy(), value.value()) {
                (true, &Json::Array(ref list)) => {
                    let alive_members: Vec<Json> = list.iter()
                        .filter_map(|m| {
                            m.as_object().and_then(|m| if m.contains_key("alive") &&
                                m["alive"].as_bool().unwrap()
                            {
                                Some(to_json(&m))
                            } else {
                                None
                            })
                        })
                        .collect();
                    let len = alive_members.len();
                    for i in 0..len {
                        let mut local_rc = rc.derive();
                        local_rc.set_local_var("@first".to_string(), to_json(&(i == 0usize)));
                        local_rc.set_local_var("@last".to_string(), to_json(&(i == len - 1)));
                        local_rc.set_local_var("@index".to_string(), to_json(&i));

                        if let Some(block_param) = h.block_param() {
                            let mut map = BTreeMap::new();
                            map.insert(block_param.to_string(), to_json(&alive_members[i]));
                            local_rc.push_block_context(&map);
                        }

                        template.render(r, &mut local_rc)?;

                        if h.block_param().is_some() {
                            local_rc.pop_block_context();
                        }
                    }
                    Ok(())
                }
                (true, &Json::Object(ref obj)) => {
                    let mut first: bool = true;
                    if !obj.contains_key("alive") || !obj["alive"].as_bool().unwrap() {
                        return Ok(());
                    }
                    for k in obj.keys() {
                        let mut local_rc = rc.derive();
                        if let Some(ref p) = local_path_root {
                            local_rc.push_local_path_root(p.clone());
                        }
                        local_rc.set_local_var("@first".to_string(), to_json(&first));
                        local_rc.set_local_var("@key".to_string(), to_json(k));

                        if first {
                            first = false;
                        }

                        if let Some(inner_path) = value.path() {
                            let new_path =
                                format!("{}/{}.[{}]", local_rc.get_path(), inner_path, k);
                            local_rc.set_path(new_path);
                        }

                        if let Some((bp_key, bp_val)) = h.block_param_pair() {
                            let mut map = BTreeMap::new();
                            map.insert(bp_key.to_string(), to_json(k));
                            map.insert(bp_val.to_string(), to_json(obj.get(k).unwrap()));
                            local_rc.push_block_context(&map);
                        }

                        template.render(r, &mut local_rc)?;

                        if h.block_param().is_some() {
                            local_rc.pop_block_context();
                        }

                        if local_path_root.is_some() {
                            local_rc.pop_local_path_root();
                        }
                    }
                    Ok(())
                }
                (false, _) => {
                    if let Some(else_template) = h.inverse() {
                        else_template.render(r, rc)?;
                    }
                    Ok(())
                }
                _ => Err(RenderError::new(
                    format!("Param type is not iterable: {:?}", template),
                )),
            };

            rc.demote_local_vars();
            return rendered;
        }
        Ok(())
    }
}

pub static EACH_ALIVE: EachAliveHelper = EachAliveHelper;
<|endoftext|>


<commit_before>//! Implementations of the low-level parser combinators.

use crate::format_description::modifier::Padding;
use core::{
    num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize},
    str::FromStr,
};

/// Marker trait for integers.
pub(crate) trait Integer: FromStr {}
impl Integer for u8 {}
impl Integer for u16 {}
impl Integer for u32 {}
impl Integer for u64 {}
impl Integer for u128 {}
impl Integer for usize {}
impl Integer for NonZeroU8 {}
impl Integer for NonZeroU16 {}
impl Integer for NonZeroU32 {}
impl Integer for NonZeroU64 {}
impl Integer for NonZeroU128 {}
impl Integer for NonZeroUsize {}

/// Call the provided parser, only mutating the original input if the final value is successful.
///
/// This is helpful when there may be multiple steps in parsing, as wrapping it with this will
/// ensure the input is never partially mutated.
pub(crate) fn lazy_mut<'a, T>(
    parser: impl Fn(&mut &'a str) -> Option<T>,
) -> impl Fn(&mut &'a str) -> Option<T> {
    move |orig_input| {
        let mut input = *orig_input;
        let value = parser(&mut input)?;
        *orig_input = input;
        Some(value)
    }
}

/// Parse a string.
pub(crate) fn string<'a, 'b: 'a>(expected: &'b str) -> impl Fn(&mut &'a str) -> Option<&'a str> {
    move |input| {
        let remaining = input.strip_prefix(expected)?;
        *input = remaining;
        Some(expected)
    }
}

/// Parse a "+" or "-" sign. Returns the ASCII byte representing the sign, if present.
pub(crate) fn sign(input: &mut &str) -> Option<char> {
    if let Some(remaining) = input.strip_prefix('-') {
        *input = remaining;
        Some('-')
    } else {
        let remaining = input.strip_prefix('+')?;
        *input = remaining;
        Some('+')
    }
}

/// Consume the first matching string, returning its associated value.
pub(crate) fn first_match<'a, 'b: 'a, T: Copy + 'a>(
    mut options: impl Iterator<Item = &'a (&'b str, T)>,
) -> impl FnMut(&mut &'b str) -> Option<T> {
    move |input| {
        options.find_map(|&(expected, t)| {
            string(expected)(input)?;
            Some(t)
        })
    }
}

/// Map the resulting value to a new value (that may or may not be the same type).
pub(crate) fn flat_map<'a, T, U>(
    parser: impl Fn(&mut &'a str) -> Option<T>,
    map_fn: impl Fn(T) -> Option<U>,
) -> impl Fn(&mut &'a str) -> Option<U> {
    lazy_mut(move |input| parser(input).and_then(|v| map_fn(v)))
}

/// Consume between `n` and `m` instances of the provided parser.
pub(crate) fn n_to_m<'a, T>(
    n: u8,
    m: u8,
    parser: impl Fn(&mut &'a str) -> Option<T>,
) -> impl Fn(&mut &'a str) -> Option<&'a str> {
    debug_assert!(m >= n);
    lazy_mut(move |input| {
        // We need to keep this to determine the total length eventually consumed.
        let orig_input = *input;

        // Mandatory
        for _ in 0..n {
            parser(input)?;
        }

        // Optional
        for _ in n..m {
            if parser(input).is_none() {
                break;
            };
        }

        Some(&orig_input[..(orig_input.len() - input.len())])
    })
}

/// Consume exactly `n` instances of the provided parser.
pub(crate) fn exactly_n<'a, T>(
    n: u8,
    parser: impl Fn(&mut &'a str) -> Option<T>,
) -> impl Fn(&mut &'a str) -> Option<&'a str> {
    n_to_m(n, n, parser)
}

/// Consume between `n` and `m` digits, returning the numerical value.
pub(crate) fn n_to_m_digits<'a, T: Integer>(n: u8, m: u8) -> impl Fn(&mut &'a str) -> Option<T> {
    debug_assert!(m >= n);
    flat_map(n_to_m(n, m, any_digit), |value| value.parse().ok())
}

/// Consume exactly `n` digits, returning the numerical value.
pub(crate) fn exactly_n_digits<'a, T: Integer>(n: u8) -> impl Fn(&mut &'a str) -> Option<T> {
    n_to_m_digits(n, n)
}

/// Consume exactly `n` digits, returning the numerical value.
pub(crate) fn exactly_n_digits_padded<'a, T: Integer>(
    n: u8,
    padding: Padding,
) -> impl Fn(&mut &'a str) -> Option<T> {
    lazy_mut(move |input| {
        if padding == Padding::None {
            n_to_m_digits(1, n)(input)
        } else if padding == Padding::Space {
            let pad_width = n_to_m(0, n, ascii_char(b' '))(input).map_or(0, |s| s.len() as u8);
            exactly_n_digits(n - pad_width)(input)
        } else {
            let pad_width = n_to_m(0, n, ascii_char(b'0'))(input).map_or(0, |s| s.len() as u8);
            exactly_n_digits(n - pad_width)(input)
        }
    })
}

/// Consume exactly one digit.
pub(crate) fn any_digit(input: &mut &str) -> Option<u8> {
    if !input.is_empty() && input.as_bytes()[0].is_ascii_digit() {
        let ret_val = input.as_bytes()[0];
        *input = &input[1..];
        Some(ret_val)
    } else {
        None
    }
}

/// Consume exactly one of the provided ASCII characters.
pub(crate) fn ascii_char(char: u8) -> impl Fn(&mut &str) -> Option<()> {
    move |input| {
        if !input.is_empty() && input.as_bytes()[0] == char {
            *input = &input[1..];
            Some(())
        } else {
            None
        }
    }
}
<commit_msg>Fix bug in parsing padding<commit_after>//! Implementations of the low-level parser combinators.

use crate::format_description::modifier::Padding;
use core::{
    num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize},
    str::FromStr,
};

/// Marker trait for integers.
pub(crate) trait Integer: FromStr {}
impl Integer for u8 {}
impl Integer for u16 {}
impl Integer for u32 {}
impl Integer for u64 {}
impl Integer for u128 {}
impl Integer for usize {}
impl Integer for NonZeroU8 {}
impl Integer for NonZeroU16 {}
impl Integer for NonZeroU32 {}
impl Integer for NonZeroU64 {}
impl Integer for NonZeroU128 {}
impl Integer for NonZeroUsize {}

/// Call the provided parser, only mutating the original input if the final value is successful.
///
/// This is helpful when there may be multiple steps in parsing, as wrapping it with this will
/// ensure the input is never partially mutated.
pub(crate) fn lazy_mut<'a, T>(
    parser: impl Fn(&mut &'a str) -> Option<T>,
) -> impl Fn(&mut &'a str) -> Option<T> {
    move |orig_input| {
        let mut input = *orig_input;
        let value = parser(&mut input)?;
        *orig_input = input;
        Some(value)
    }
}

/// Parse a string.
pub(crate) fn string<'a, 'b: 'a>(expected: &'b str) -> impl Fn(&mut &'a str) -> Option<&'a str> {
    move |input| {
        *input = input.strip_prefix(expected)?;
        Some(expected)
    }
}

/// Parse a "+" or "-" sign. Returns the ASCII byte representing the sign, if present.
pub(crate) fn sign(input: &mut &str) -> Option<char> {
    if let Some(remaining) = input.strip_prefix('-') {
        *input = remaining;
        Some('-')
    } else {
        let remaining = input.strip_prefix('+')?;
        *input = remaining;
        Some('+')
    }
}

/// Consume the first matching string, returning its associated value.
pub(crate) fn first_match<'a, 'b: 'a, T: Copy + 'a>(
    mut options: impl Iterator<Item = &'a (&'b str, T)>,
) -> impl FnMut(&mut &'b str) -> Option<T> {
    move |input| {
        options.find_map(|&(expected, t)| {
            string(expected)(input)?;
            Some(t)
        })
    }
}

/// Map the resulting value to a new value (that may or may not be the same type).
pub(crate) fn flat_map<'a, T, U>(
    parser: impl Fn(&mut &'a str) -> Option<T>,
    map_fn: impl Fn(T) -> Option<U>,
) -> impl Fn(&mut &'a str) -> Option<U> {
    lazy_mut(move |input| parser(input).and_then(|v| map_fn(v)))
}

/// Consume between `n` and `m` instances of the provided parser.
pub(crate) fn n_to_m<'a, T>(
    n: u8,
    m: u8,
    parser: impl Fn(&mut &'a str) -> Option<T>,
) -> impl Fn(&mut &'a str) -> Option<&'a str> {
    debug_assert!(m >= n);
    lazy_mut(move |input| {
        // We need to keep this to determine the total length eventually consumed.
        let orig_input = *input;

        // Mandatory
        for _ in 0..n {
            parser(input)?;
        }

        // Optional
        for _ in n..m {
            if parser(input).is_none() {
                break;
            };
        }

        Some(&orig_input[..(orig_input.len() - input.len())])
    })
}

/// Consume exactly `n` instances of the provided parser.
pub(crate) fn exactly_n<'a, T>(
    n: u8,
    parser: impl Fn(&mut &'a str) -> Option<T>,
) -> impl Fn(&mut &'a str) -> Option<&'a str> {
    n_to_m(n, n, parser)
}

/// Consume between `n` and `m` digits, returning the numerical value.
pub(crate) fn n_to_m_digits<'a, T: Integer>(n: u8, m: u8) -> impl Fn(&mut &'a str) -> Option<T> {
    debug_assert!(m >= n);
    flat_map(n_to_m(n, m, any_digit), |value| value.parse().ok())
}

/// Consume exactly `n` digits, returning the numerical value.
pub(crate) fn exactly_n_digits<'a, T: Integer>(n: u8) -> impl Fn(&mut &'a str) -> Option<T> {
    n_to_m_digits(n, n)
}

/// Consume exactly `n` digits, returning the numerical value.
pub(crate) fn exactly_n_digits_padded<'a, T: Integer>(
    n: u8,
    padding: Padding,
) -> impl Fn(&mut &'a str) -> Option<T> {
    lazy_mut(move |input| {
        if padding == Padding::None {
            n_to_m_digits(1, n)(input)
        } else if padding == Padding::Space {
            let pad_width = n_to_m(0, n - 1, ascii_char(b' '))(input).map_or(0, |s| s.len() as u8);
            exactly_n_digits(n - pad_width)(input)
        } else {
            let pad_width = n_to_m(0, n - 1, ascii_char(b'0'))(input).map_or(0, |s| s.len() as u8);
            exactly_n_digits(n - pad_width)(input)
        }
    })
}

/// Consume exactly one digit.
pub(crate) fn any_digit(input: &mut &str) -> Option<u8> {
    match input.as_bytes() {
        [c, ..] if c.is_ascii_digit() => {
            *input = &input[1..];
            Some(*c)
        }
        _ => None,
    }
}

/// Consume exactly one of the provided ASCII characters.
pub(crate) fn ascii_char(char: u8) -> impl Fn(&mut &str) -> Option<()> {
    move |input| match input.as_bytes() {
        [c, ..] if *c == char => {
            *input = &input[1..];
            Some(())
        }
        _ => None,
    }
}
<|endoftext|>