<commit_before>// encoding.rs

// import items in baseNN.rs
import Base16         = baseNN::Base16;
import Base32         = baseNN::Base32;
import Base64         = baseNN::Base64;

// import constants in baseNN/base{16,32,64}.rs
import BASE16         = baseNN::base16::BASE16;
import BASE32         = baseNN::base32::BASE32_STD;
import BASE64         = baseNN::base64::BASE64_STD;
import BASE32_HEX     = baseNN::base32::BASE32_HEX;
import BASE64_URL     = baseNN::base64::BASE64_URL;

// import structs in baseNN/base{16,32,64}.rs
import Base16Writer   = baseNN::base16::Base16Writer;
import Base32Writer   = baseNN::base32::Base32Writer;
import Base64Writer   = baseNN::base64::Base64Writer;
import Base32Reader   = baseNN::base32::Base32Reader;
import Base64Reader   = baseNN::base64::Base64Reader;

//===-------------------------------------------------------------------===//
//                              b a s e N N
//===-------------------------------------------------------------------===//

// XXX this line is required to resolve traits in baseNN.
export baseNN;

// export all BaseNN traits
export Base16;
export Base32;
export Base64;

// export constants
export BASE16;
export BASE32;
export BASE64;
export BASE32_HEX;
export BASE64_URL;

// export structs
export Base16Writer;
export Base32Writer;
export Base64Writer;
export Base32Reader;
export Base64Reader;

<commit_msg>Update comment<commit_after>// encoding.rs

// import traits in baseNN.rs
import Base16         = baseNN::Base16;
import Base32         = baseNN::Base32;
import Base64         = baseNN::Base64;

// import constants in baseNN/base{16,32,64}.rs
import BASE16         = baseNN::base16::BASE16;
import BASE32         = baseNN::base32::BASE32_STD;
import BASE64         = baseNN::base64::BASE64_STD;
import BASE32_HEX     = baseNN::base32::BASE32_HEX;
import BASE64_URL     = baseNN::base64::BASE64_URL;

// import structs in baseNN/base{16,32,64}.rs
import Base16Writer   = baseNN::base16::Base16Writer;
import Base32Writer   = baseNN::base32::Base32Writer;
import Base64Writer   = baseNN::base64::Base64Writer;
import Base32Reader   = baseNN::base32::Base32Reader;
import Base64Reader   = baseNN::base64::Base64Reader;

//===-------------------------------------------------------------------===//
//                              b a s e N N
//===-------------------------------------------------------------------===//

// XXX this line is required to resolve traits in baseNN.
export baseNN;

// export all BaseNN traits
export Base16;
export Base32;
export Base64;

// export constants
export BASE16;
export BASE32;
export BASE64;
export BASE32_HEX;
export BASE64_URL;

// export structs
export Base16Writer;
export Base32Writer;
export Base64Writer;
export Base32Reader;
export Base64Reader;

<|endoftext|>


<commit_before>use cgmath::{Aabb3};
use std::sync::Mutex;
use stopwatch;
use time;

use common::entity_id;
use common::fnv_map;
use common::id_allocator;
use common::voxel;

use in_progress_terrain;
use lod;
use physics::Physics;
use terrain;
use update_gaia;
use update_gaia::LoadReason;

// TODO: Consider factoring this logic such that what to load is separated from how it's loaded.

/// Load and unload terrain::TerrainBlocks from the game.
/// Each terrain::TerrainBlock can be owned by a set of owners, each of which can independently request LODs.
/// The maximum lod::T requested is the one that is actually loaded.
pub struct T {
  pub terrain: terrain::T,
  pub in_progress_terrain: Mutex<in_progress_terrain::T>,
  pub lod_map: Mutex<lod::Map>,
  pub loaded: Mutex<fnv_map::T<voxel::bounds::T, Vec<entity_id::T>>>,
}

impl T {
  pub fn new() -> T {
    T {
      terrain: terrain::T::new(terrain::Seed::new(0)),
      in_progress_terrain: Mutex::new(in_progress_terrain::T::new()),
      lod_map: Mutex::new(lod::Map::new()),
      loaded: Mutex::new(fnv_map::new()),
    }
  }

  // TODO: Avoid the double-lookup when unload and load the same index.

  pub fn load<LoadBlock>(
    &self,
    id_allocator: &Mutex<id_allocator::T<entity_id::T>>,
    physics: &Mutex<Physics>,
    block_position: &voxel::bounds::T,
    new_lod: lod::T,
    owner: lod::OwnerId,
    load_block: &mut LoadBlock,
  ) where LoadBlock: FnMut(update_gaia::Message)
  {
    let prev_lod;
    let max_lod_changed: bool;
    let mut lod_map = self.lod_map.lock().unwrap();
    let mut in_progress_terrain = self.in_progress_terrain.lock().unwrap();
    match lod_map.get(block_position, owner) {
      Some((Some(prev), lods)) => {
        prev_lod = Some(prev);
        if new_lod == prev {
          return;
        }

        if new_lod < prev {
          max_lod_changed = lods.iter().filter(|&&(_, l)| l >= prev).count() < 2;
        } else {
          max_lod_changed = lods.iter().filter(|&&(_, l)| l >= new_lod).count() == 0;
        }
      },
      Some((None, lods)) => {
        max_lod_changed = lods.iter().filter(|&&(_, l)| l >= new_lod).count() == 0;
        prev_lod = None;
      },
      None => {
        max_lod_changed = true;
        prev_lod = None;
      },
    }

    if !max_lod_changed {
      // Maximum lod::T is unchanged.
      let (_, change) = lod_map.insert(*block_position, new_lod, owner);
      assert!(change.is_none());
      return;
    }

    match new_lod {
      lod::Placeholder => {
        let (_, change) = lod_map.insert(*block_position, new_lod, owner);
        let change = change.unwrap();
        assert!(change.loaded == None);
        assert!(prev_lod == None);
        assert!(change.desired == Some(lod::Placeholder));
        in_progress_terrain.insert(id_allocator, physics, block_position);
      },
      lod::Full => {
        let mut generate_block = || {
          debug!("{:?} requested from gaia", block_position);
          load_block(
            update_gaia::Message::Load(time::precise_time_ns(), vec!(*block_position), LoadReason::Local(owner))
          );
        };
        generate_block();
      },
    };
  }

  pub fn insert_block(
    block: &LoadedTerrain,
    position: &voxel::bounds::T,
    owner: lod::OwnerId,
    physics: &Mutex<Physics>,
    lod_map: &mut lod::Map,
    in_progress_terrain: &mut in_progress_terrain::T,
    loaded: &mut fnv_map::T<voxel::bounds::T, Vec<entity_id::T>>,
  ) {
    let lod = lod::Full;
    let (_, change) = lod_map.insert(*position, lod, owner);
    // TODO: This should be an unwrap, but the preconditions of another TODO aren't
    // satisfied in src/update_gaia.rs.
    // (i.e. blocks sometimes get here when they're stale).
    let change = match change {
      None => return,
      Some(change) => change,
    };
    assert!(change.desired == Some(lod));
    change.loaded.map(|loaded_lod|
      match loaded_lod {
        lod::Placeholder => {
          in_progress_terrain.remove(physics, position);
        }
        lod::Full => {
          stopwatch::time("terrain_loader.load.unload", || {
            let ids = loaded.get(position).unwrap();
            let mut physics = physics.lock().unwrap();
            for id in ids {
              physics.remove_terrain(*id);
            }
          });
        },
      }
    );

    stopwatch::time("terrain_loader.load.physics", || {
      let mut physics = physics.lock().unwrap();
      for &(ref id, ref bounds) in &block.bounds {
        physics.insert_terrain(*id, bounds);
      }
    });
  }

  pub fn unload(
    &self,
    physics: &Mutex<Physics>,
    block_position: &voxel::bounds::T,
    owner: lod::OwnerId,
  ) {
    let (_, mlod_change) =
      self.lod_map.lock().unwrap().remove(*block_position, owner);

    let lod_change;
    match mlod_change {
      None => {
        return;
      },
      Some(c) => lod_change = c,
    }

    lod_change.loaded.map(|loaded_lod| {
      match loaded_lod {
        lod::Placeholder => {
          self.in_progress_terrain.lock().unwrap().remove(physics, block_position);
        }
        lod::Full => {
          stopwatch::time("terrain_loader.unload", || {
            match self.loaded.lock().unwrap().get(block_position) {
              None => {
                // Unloaded before the load request completed.
              },
              Some(ids) => {
                let mut physics = physics.lock().unwrap();
                for id in ids {
                  physics.remove_terrain(*id);
                }
              },
            }
          });
        },
      }
    });
  }
}

pub struct LoadedTerrain {
  pub bounds: Vec<(entity_id::T, Aabb3<f32>)>,
}
<commit_msg>fallout from similar_names lnit<commit_after>use cgmath::{Aabb3};
use std::sync::Mutex;
use stopwatch;
use time;

use common::entity_id;
use common::fnv_map;
use common::id_allocator;
use common::voxel;

use in_progress_terrain;
use lod;
use physics::Physics;
use terrain;
use update_gaia;
use update_gaia::LoadReason;

// TODO: Consider factoring this logic such that what to load is separated from how it's loaded.

/// Load and unload terrain::TerrainBlocks from the game.
/// Each terrain::TerrainBlock can be owned by a set of owners, each of which can independently request LODs.
/// The maximum lod::T requested is the one that is actually loaded.
pub struct T {
  pub terrain: terrain::T,
  pub in_progress_terrain: Mutex<in_progress_terrain::T>,
  pub lod_map: Mutex<lod::Map>,
  pub loaded: Mutex<fnv_map::T<voxel::bounds::T, Vec<entity_id::T>>>,
}

impl T {
  pub fn new() -> T {
    T {
      terrain: terrain::T::new(terrain::Seed::new(0)),
      in_progress_terrain: Mutex::new(in_progress_terrain::T::new()),
      lod_map: Mutex::new(lod::Map::new()),
      loaded: Mutex::new(fnv_map::new()),
    }
  }

  // TODO: Avoid the double-lookup when unload and load the same index.

  pub fn load<LoadBlock>(
    &self,
    id_allocator: &Mutex<id_allocator::T<entity_id::T>>,
    physics: &Mutex<Physics>,
    block_position: &voxel::bounds::T,
    new_lod: lod::T,
    owner: lod::OwnerId,
    load_block: &mut LoadBlock,
  ) where LoadBlock: FnMut(update_gaia::Message)
  {
    let prev_lod;
    let max_lod_changed: bool;
    let mut lod_map = self.lod_map.lock().unwrap();
    let mut in_progress_terrain = self.in_progress_terrain.lock().unwrap();
    match lod_map.get(block_position, owner) {
      Some((Some(prev), lods)) => {
        prev_lod = Some(prev);
        if new_lod == prev {
          return;
        }

        if new_lod < prev {
          max_lod_changed = lods.iter().filter(|&&(_, l)| l >= prev).count() < 2;
        } else {
          max_lod_changed = lods.iter().filter(|&&(_, l)| l >= new_lod).count() == 0;
        }
      },
      Some((None, lods)) => {
        max_lod_changed = lods.iter().filter(|&&(_, l)| l >= new_lod).count() == 0;
        prev_lod = None;
      },
      None => {
        max_lod_changed = true;
        prev_lod = None;
      },
    }

    if !max_lod_changed {
      // Maximum lod::T is unchanged.
      let (_, change) = lod_map.insert(*block_position, new_lod, owner);
      assert!(change.is_none());
      return;
    }

    match new_lod {
      lod::Placeholder => {
        let (_, change) = lod_map.insert(*block_position, new_lod, owner);
        let change = change.unwrap();
        assert!(change.loaded == None);
        assert!(prev_lod == None);
        assert!(change.desired == Some(lod::Placeholder));
        in_progress_terrain.insert(id_allocator, physics, block_position);
      },
      lod::Full => {
        let mut generate_block = || {
          debug!("{:?} requested from gaia", block_position);
          load_block(
            update_gaia::Message::Load(time::precise_time_ns(), vec!(*block_position), LoadReason::Local(owner))
          );
        };
        generate_block();
      },
    };
  }

  pub fn insert_block(
    block: &LoadedTerrain,
    position: &voxel::bounds::T,
    owner: lod::OwnerId,
    physics: &Mutex<Physics>,
    lod_map: &mut lod::Map,
    in_progress_terrain: &mut in_progress_terrain::T,
    loaded: &mut fnv_map::T<voxel::bounds::T, Vec<entity_id::T>>,
  ) {
    let lod = lod::Full;
    let (_, change) = lod_map.insert(*position, lod, owner);
    // TODO: This should be an unwrap, but the preconditions of another TODO aren't
    // satisfied in src/update_gaia.rs.
    // (i.e. blocks sometimes get here when they're stale).
    let change = match change {
      None => return,
      Some(change) => change,
    };
    assert!(change.desired == Some(lod));
    change.loaded.map(|loaded_lod|
      match loaded_lod {
        lod::Placeholder => {
          in_progress_terrain.remove(physics, position);
        }
        lod::Full => {
          stopwatch::time("terrain_loader.load.unload", || {
            let ids = loaded.get(position).unwrap();
            let mut physics = physics.lock().unwrap();
            for id in ids {
              physics.remove_terrain(*id);
            }
          });
        },
      }
    );

    stopwatch::time("terrain_loader.load.physics", || {
      let mut physics = physics.lock().unwrap();
      for &(ref id, ref bounds) in &block.bounds {
        physics.insert_terrain(*id, bounds);
      }
    });
  }

  pub fn unload(
    &self,
    physics: &Mutex<Physics>,
    block_position: &voxel::bounds::T,
    owner: lod::OwnerId,
  ) {
    let lod_change;
    match self.lod_map.lock().unwrap().remove(*block_position, owner) {
      (_, None) => return,
      (_, Some(c)) => lod_change = c,
    }

    lod_change.loaded.map(|loaded_lod| {
      match loaded_lod {
        lod::Placeholder => {
          self.in_progress_terrain.lock().unwrap().remove(physics, block_position);
        }
        lod::Full => {
          stopwatch::time("terrain_loader.unload", || {
            match self.loaded.lock().unwrap().get(block_position) {
              None => {
                // Unloaded before the load request completed.
              },
              Some(ids) => {
                let mut physics = physics.lock().unwrap();
                for id in ids {
                  physics.remove_terrain(*id);
                }
              },
            }
          });
        },
      }
    });
  }
}

pub struct LoadedTerrain {
  pub bounds: Vec<(entity_id::T, Aabb3<f32>)>,
}
<|endoftext|>


<commit_before>
use std::io;
use std::slice::Iter;

use parser::ast::*;
use parser::store::*;
use output::structs::*;
use output::client_html::*;
use output::client_js::*;

pub struct FormatHtml<'input> {
    doc: &'input DocumentState<'input>,
    events_vec: EventsVec,
    keys_vec: Vec<String>,
    output_html: WriteHtmlOpsContent<'input>
}

impl<'input> FormatHtml<'input> {
    pub fn with_doc<'inp>(doc: &'inp DocumentState<'inp>) -> FormatHtml<'inp> {
        FormatHtml {
            doc: doc,
            events_vec: Default::default(),
            keys_vec: Default::default(),
            output_html: WriteHtmlOpsContent::with_doc(doc)
        }
    }

    pub fn write_js_store(&mut self,
                          w: &mut io::Write,
                          resolve: &ResolveVars)
                          -> Result {
        // TODO: Implement default scope?

        // Generate script
        for (ref reducer_key, ref reducer_data) in self.doc.reducer_key_data.iter() {
            writeln!(w, "  function {}Reducer(state, action) {{", reducer_key)?;

            let reducer_scope = resolve.with_state_key(reducer_key);

            if let Some(ref actions) = reducer_data.actions {
                for ref action_data in actions {
                    let action_ty = reducer_scope.action_type(&action_data.action_type);

                    match &action_data.state_expr {
                        &Some(ActionStateExprType::SimpleReducerKeyExpr(ref simple_expr)) => {
                            let action_scope = reducer_scope.action_result(reducer_key);
                            writeln!(w,
                                     "if ('undefined' !== typeof action && '{}' == action.type) \
                                      {{",
                                     action_ty)
                                ?;
                            write!(w, "  return ")?;
                            // write!(w, "Object.assign({{ \"{}\": ", reducer_key)?;
                            write_js_expr_value(w, simple_expr, &self.doc, &action_scope)?;
                            writeln!(w, ";")?;
                            // writeln!(w, "}})")?;
                            writeln!(w, "}}")?;
                        }
                        _ => {}
                    }
                }
            }

            // Default expression used to initialize state
            write!(w, "    return state || ")?;
            if let Some(ref default_expr) = reducer_data.default_expr {
                // write!(w, "Object.assign({{ \"{}\": ", reducer_key)?;
                write_js_expr_value(w, default_expr, &mut self.doc, &resolve)?;
                // write!(w, "}})")?;
            } else {
                write!(w, "null")?;
            }
            writeln!(w, ";")?;

            writeln!(w, "  }}")?;
        }

        writeln!(w, "  var rootReducer = Redux.combineReducers({{")?;
        for (ref reducer_key, _) in self.doc.reducer_key_data.iter() {
            writeln!(w, "    {}: {}Reducer,", &reducer_key, &reducer_key)?;
        }
        writeln!(w, "  }});")?;

        writeln!(w, "  var store = Redux.createStore(rootReducer, {{}});")?;

        Ok(())
    }

    #[allow(unused_variables)]
    pub fn write_js_event_bindings(&self,
                                   w: &mut io::Write,
                                   events_iter: Iter<EventsItem>,
                                   resolve: &ResolveVars)
                                   -> Result {
        writeln!(w, "      // Bind actions")?;
        for &(ref element_key, ref event_name, ref params, ref action_ops, ref event_scope) in
            events_iter {
            let event_name = event_name.as_ref().map(String::as_str).map_or("click", |s| s);
            writeln!(w,
                     "  document.querySelector(\"[key='{}']\").addEventListener(\"{}\", \
                      function(event) {{",
                     element_key,
                     event_name)
                ?;

            let resolve = resolve;

            if let &Some(ref action_ops) = action_ops {
                let action_scope = event_scope.as_ref()
                    .map(|event_scope| resolve.with_state_key(event_scope));
                let resolve = action_scope.as_ref().map_or(resolve, |r| r);

                for ref action_op in action_ops {
                    match *action_op {
                        &ActionOpNode::DispatchAction(ref action_key, ref action_params) => {
                            let action_ty = resolve.action_type(action_key.as_str());
                            /*
                            // TODO: Fix type
                            let action_prefix = scope.as_ref()
                                .map_or("".into(), |s| s.to_uppercase());
                            let action_ty =
                                format!("{}.{}", action_prefix, action_key.to_uppercase());
                            */
                            writeln!(w, " store.dispatch({{\"type\": \"{}\"}}); ", action_ty)?;
                        }
                    }
                }
            }
            writeln!(w, "  }});")?;
        }
        Ok(())
    }

    #[allow(dead_code)]
    #[allow(unused_variables)]
    pub fn write_html_document(&mut self, w: &mut io::Write) -> Result {
        // Output state
        // let mut events_vec: EventsVec = Default::default();
        // let mut keys_vec: Vec<String> = Default::default();

        // Output
        write!(w, "{}", indoc!(r#"
            <!doctype HTML>

        "#))?;

        // FIXME
        // let resolve = ResolveVars::default_resolver("counter");
        let resolve = ResolveVars::default_resolver();

        let ops_iter = self.doc.root_block.ops_vec.iter();

        self.output_html.write_html_ops_content(w, ops_iter, &resolve, None)?;

        write!(w,
               "{}",
               indoc!(r#"

        "#))
            ?;

        Ok(())
    }
}
<commit_msg>Remove events_vec and keys_vec from FormatHtml (now in WriteHtmlOpsContent)<commit_after>
use std::io;
use std::slice::Iter;

use parser::ast::*;
use parser::store::*;
use output::structs::*;
use output::client_html::*;
use output::client_js::*;

pub struct FormatHtml<'input> {
    doc: &'input DocumentState<'input>,
    output_html: WriteHtmlOpsContent<'input>
}

impl<'input> FormatHtml<'input> {
    pub fn with_doc<'inp>(doc: &'inp DocumentState<'inp>) -> FormatHtml<'inp> {
        FormatHtml {
            doc: doc,
            output_html: WriteHtmlOpsContent::with_doc(doc)
        }
    }

    pub fn write_js_store(&mut self,
                          w: &mut io::Write,
                          resolve: &ResolveVars)
                          -> Result {
        // TODO: Implement default scope?

        // Generate script
        for (ref reducer_key, ref reducer_data) in self.doc.reducer_key_data.iter() {
            writeln!(w, "  function {}Reducer(state, action) {{", reducer_key)?;

            let reducer_scope = resolve.with_state_key(reducer_key);

            if let Some(ref actions) = reducer_data.actions {
                for ref action_data in actions {
                    let action_ty = reducer_scope.action_type(&action_data.action_type);

                    match &action_data.state_expr {
                        &Some(ActionStateExprType::SimpleReducerKeyExpr(ref simple_expr)) => {
                            let action_scope = reducer_scope.action_result(reducer_key);
                            writeln!(w,
                                     "if ('undefined' !== typeof action && '{}' == action.type) \
                                      {{",
                                     action_ty)
                                ?;
                            write!(w, "  return ")?;
                            // write!(w, "Object.assign({{ \"{}\": ", reducer_key)?;
                            write_js_expr_value(w, simple_expr, &self.doc, &action_scope)?;
                            writeln!(w, ";")?;
                            // writeln!(w, "}})")?;
                            writeln!(w, "}}")?;
                        }
                        _ => {}
                    }
                }
            }

            // Default expression used to initialize state
            write!(w, "    return state || ")?;
            if let Some(ref default_expr) = reducer_data.default_expr {
                // write!(w, "Object.assign({{ \"{}\": ", reducer_key)?;
                write_js_expr_value(w, default_expr, &mut self.doc, &resolve)?;
                // write!(w, "}})")?;
            } else {
                write!(w, "null")?;
            }
            writeln!(w, ";")?;

            writeln!(w, "  }}")?;
        }

        writeln!(w, "  var rootReducer = Redux.combineReducers({{")?;
        for (ref reducer_key, _) in self.doc.reducer_key_data.iter() {
            writeln!(w, "    {}: {}Reducer,", &reducer_key, &reducer_key)?;
        }
        writeln!(w, "  }});")?;

        writeln!(w, "  var store = Redux.createStore(rootReducer, {{}});")?;

        Ok(())
    }

    #[allow(unused_variables)]
    pub fn write_js_event_bindings(&self,
                                   w: &mut io::Write,
                                   events_iter: Iter<EventsItem>,
                                   resolve: &ResolveVars)
                                   -> Result {
        writeln!(w, "      // Bind actions")?;
        for &(ref element_key, ref event_name, ref params, ref action_ops, ref event_scope) in
            events_iter {
            let event_name = event_name.as_ref().map(String::as_str).map_or("click", |s| s);
            writeln!(w,
                     "  document.querySelector(\"[key='{}']\").addEventListener(\"{}\", \
                      function(event) {{",
                     element_key,
                     event_name)
                ?;

            let resolve = resolve;

            if let &Some(ref action_ops) = action_ops {
                let action_scope = event_scope.as_ref()
                    .map(|event_scope| resolve.with_state_key(event_scope));
                let resolve = action_scope.as_ref().map_or(resolve, |r| r);

                for ref action_op in action_ops {
                    match *action_op {
                        &ActionOpNode::DispatchAction(ref action_key, ref action_params) => {
                            let action_ty = resolve.action_type(action_key.as_str());
                            /*
                            // TODO: Fix type
                            let action_prefix = scope.as_ref()
                                .map_or("".into(), |s| s.to_uppercase());
                            let action_ty =
                                format!("{}.{}", action_prefix, action_key.to_uppercase());
                            */
                            writeln!(w, " store.dispatch({{\"type\": \"{}\"}}); ", action_ty)?;
                        }
                    }
                }
            }
            writeln!(w, "  }});")?;
        }
        Ok(())
    }

    #[allow(dead_code)]
    #[allow(unused_variables)]
    pub fn write_html_document(&mut self, w: &mut io::Write) -> Result {
        // Output state
        // let mut events_vec: EventsVec = Default::default();
        // let mut keys_vec: Vec<String> = Default::default();

        // Output
        write!(w, "{}", indoc!(r#"
            <!doctype HTML>

        "#))?;

        // FIXME
        // let resolve = ResolveVars::default_resolver("counter");
        let resolve = ResolveVars::default_resolver();

        let ops_iter = self.doc.root_block.ops_vec.iter();

        self.output_html.write_html_ops_content(w, ops_iter, &resolve, None)?;

        write!(w,
               "{}",
               indoc!(r#"

        "#))
            ?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>use Module;
use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Gain {
    LV,
    HV,
}

impl ::std::convert::Into<String> for Gain {
    fn into(self) -> String {
        let s = match self {
            Gain::LV => "LV",
            Gain::HV => "HV",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for Gain {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "LV" => Ok(Gain::LV),
            "HV" => Ok(Gain::HV),
            gain => Err(format!("Unknow gain '{}'", gain)),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Source {
    IN1,
    IN2,
}

impl ::std::convert::Into<String> for Source {
    fn into(self) -> String {
        let s = match self {
            Source::IN1 => "SOUR1",
            Source::IN2 => "SOUR2",
        };

        String::from(s)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Decimation {
    DEC_1,
    DEC_8,
    DEC_64,
    DEC_1024,
    DEC_8192,
    DEC_65536,
}

impl ::std::convert::Into<String> for Decimation {
    fn into(self) -> String {
        let s = match self {
            Decimation::DEC_1 => "1",
            Decimation::DEC_8 => "8",
            Decimation::DEC_64 => "64",
            Decimation::DEC_1024 => "1024",
            Decimation::DEC_8192 => "8192",
            Decimation::DEC_65536 => "65536",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for Decimation {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "1" => Ok(Decimation::DEC_1),
            "8" => Ok(Decimation::DEC_8),
            "64" => Ok(Decimation::DEC_64),
            "1024" => Ok(Decimation::DEC_1024),
            "8192" => Ok(Decimation::DEC_8192),
            "65536" => Ok(Decimation::DEC_65536),
            decimation => Err(format!("Unknow decimation '{}'", decimation)),
        }
    }
}

impl ::std::convert::Into<SamplingRate> for Decimation {
    fn into(self) -> SamplingRate {
        match self {
            Decimation::DEC_1 => SamplingRate::RATE_125MHz,
            Decimation::DEC_8 => SamplingRate::RATE_15_6MHz,
            Decimation::DEC_64 => SamplingRate::RATE_1_9MHz,
            Decimation::DEC_1024 => SamplingRate::RATE_103_8kHz,
            Decimation::DEC_8192 => SamplingRate::RATE_15_2kHz,
            Decimation::DEC_65536 => SamplingRate::RATE_1_9kHz,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SamplingRate {
    RATE_125MHz,
    RATE_15_6MHz,
    RATE_1_9MHz,
    RATE_103_8kHz,
    RATE_15_2kHz,
    RATE_1_9kHz,
}

impl SamplingRate {
    pub fn get_buffer_duration(self) -> ::std::time::Duration {
        let (s, ns) = match self {
            SamplingRate::RATE_125MHz => (0, 131_072),
            SamplingRate::RATE_15_6MHz => (0, 1_049_000),
            SamplingRate::RATE_1_9MHz => (0, 8_389_000),
            SamplingRate::RATE_103_8kHz => (0, 134_218_000),
            SamplingRate::RATE_15_2kHz => (1, 740_000_000),
            SamplingRate::RATE_1_9kHz => (8, 590_000_000),
        };

        ::std::time::Duration::new(s, ns)
    }
}

impl ::std::fmt::Display for SamplingRate {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &SamplingRate::RATE_125MHz => "125 MHz",
            &SamplingRate::RATE_15_6MHz => "15.6 MHz",
            &SamplingRate::RATE_1_9MHz => "1.9 MHz",
            &SamplingRate::RATE_103_8kHz => "103.8 kHz",
            &SamplingRate::RATE_15_2kHz => "15.2 kHz",
            &SamplingRate::RATE_1_9kHz => "1.9 kHz",
        };

        write!(f, "{}", display)
    }
}

impl ::std::convert::Into<String> for SamplingRate {
    fn into(self) -> String {
        let s = match self {
            SamplingRate::RATE_125MHz => "125MHz",
            SamplingRate::RATE_15_6MHz => "15_6MHz",
            SamplingRate::RATE_1_9MHz => "1_9MHz",
            SamplingRate::RATE_103_8kHz => "103_8kHz",
            SamplingRate::RATE_15_2kHz => "15_2kHz",
            SamplingRate::RATE_1_9kHz => "1_9kHz",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for SamplingRate {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "125000000 Hz" => Ok(SamplingRate::RATE_125MHz),
            "15600000 Hz" => Ok(SamplingRate::RATE_15_6MHz),
            "1900000 Hz" => Ok(SamplingRate::RATE_1_9MHz),
            "103800 Hz" => Ok(SamplingRate::RATE_103_8kHz),
            "15200 Hz" => Ok(SamplingRate::RATE_15_2kHz),
            "1900 Hz" => Ok(SamplingRate::RATE_1_9kHz),
            rate => Err(format!("Unknow sampling rate {}", rate)),
        }
    }
}

#[derive(Clone)]
pub struct Acquire {
    socket: ::std::cell::RefCell<Socket>,
    started: bool,
}

impl ::Module for Acquire {
    fn get_socket<'a>(&'a self) -> ::std::cell::RefMut<'a, ::socket::Socket> {
        self.socket.borrow_mut()
    }
}

impl Acquire {
    pub fn new(socket: Socket) -> Self {
        Acquire {
            socket: ::std::cell::RefCell::new(socket),
            started: false,
        }
    }

    /**
     * Starts acquisition.
     */
    pub fn start(&mut self) {
        self.send("ACQ:START");
        self.started = true;
    }

    /**
     * Stops acquisition.
     */
    pub fn stop(&mut self) {
        self.send("ACQ:STOP");
        self.started = false;
    }

    pub fn is_started(&self) -> bool {
        self.started
    }

    /**
     * Stops acquisition and sets all parameters to default values.
     */
    pub fn reset(&self) {
        self.send("ACQ:RST");
    }

    /**
     * Set decimation factor.
     */
    pub fn set_decimation(&self, decimation: Decimation) {
        self.send(format!("ACQ:DEC {}", Into::<String>::into(decimation)));
    }

    /**
     * Get decimation factor.
     */
    pub fn get_decimation(&self) -> Result<Decimation, String> {
        self.send("ACQ:DEC?");

        self.receive()
            .parse()
    }

    /**
     * Get sampling rate.
     *
     * @warning Calling this command makes buffer overflow.
     * See https://github.com/RedPitaya/RedPitaya/pull/110
     */
    pub fn get_sampling_rate(&self) -> Result<SamplingRate, String> {
        self.send("ACQ:SRAT?");

        self.receive()
            .parse()
    }

    /**
     * Enable averaging.
     */
    pub fn enable_average(&self) {
        self.send("ACQ:AVG ON");
    }

    /**
     * Disable averaging.
     */
    pub fn disable_average(&self) {
        self.send("ACQ:AVG OFF");
    }

    /**
     * Get averaging status.
     */
    pub fn is_average_enabled(&self) -> bool {
        self.send("ACQ:AVG?");

        let message = self.receive();

        match message.as_str() {
            "ON" => true,
            _ => false,
        }
    }

    /**
     * Set gain settings to HIGH or LOW.
     *
     * This gain is referring to jumper settings on Red Pitaya fast analog inputs.
     */
    pub fn set_gain(&self, source: Source, gain: Gain) {
        self.send(format!("ACQ:{}:GAIN {}", Into::<String>::into(source), Into::<String>::into(gain)));
    }

    /**
     * Get gain settings to HIGH or LOW.
     */
    pub fn get_gain(&self, source: Source) -> Result<Gain, String> {
        self.send(format!("ACQ:{}:GAIN?", Into::<String>::into(source)));

        self.receive()
            .parse()
    }
}

#[cfg(test)]
mod test {
    macro_rules! acquire_assert {
        ($f:ident, $e:expr) => {
            let (rx, acquire) = create_acquire();

            acquire.$f();
            assert_eq!($e, rx.recv().unwrap());
        }
    }

    #[test]
    fn test_sampling_rate_get_buffer_duration() {
        let duration = ::std::time::Duration::new(8, 590_000_000);

        assert_eq!(duration, ::acquire::SamplingRate::RATE_1_9kHz.get_buffer_duration());
    }

    #[test]
    fn test_start() {
        let (rx, mut acquire) = create_acquire();

        acquire.start();
        assert_eq!("ACQ:START\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_stop() {
        let (rx, mut acquire) = create_acquire();

        acquire.stop();
        assert_eq!("ACQ:STOP\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_is_started() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.is_started(), false);
        acquire.start();
        assert_eq!(acquire.is_started(), true);
        acquire.stop();
        assert_eq!(acquire.is_started(), false);
    }

    #[test]
    fn test_reset() {
        acquire_assert!(reset, "ACQ:RST\r\n");
    }

    #[test]
    fn test_set_decimation() {
        let (rx, acquire) = create_acquire();

        acquire.set_decimation(::acquire::Decimation::DEC_8);
        assert_eq!("ACQ:DEC 8\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_decimation() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.get_decimation(), Ok(::acquire::Decimation::DEC_1));
    }

    #[test]
    fn test_get_sampling_rate() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.get_sampling_rate(), Ok(::acquire::SamplingRate::RATE_125MHz));
    }

    #[test]
    fn test_enable_average() {
        acquire_assert!(enable_average, "ACQ:AVG ON\r\n");
    }

    #[test]
    fn test_disable_average() {
        acquire_assert!(disable_average, "ACQ:AVG OFF\r\n");
    }

    #[test]
    fn test_is_average_enabled() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.is_average_enabled(), true);
    }

    #[test]
    fn test_set_gain() {
        let (rx, acquire) = create_acquire();

        acquire.set_gain(::acquire::Source::IN1, ::acquire::Gain::LV);
        assert_eq!("ACQ:SOUR1:GAIN LV\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_gain() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.get_gain(::acquire::Source::IN1), Ok(::acquire::Gain::HV));
    }

    fn create_acquire() -> (::std::sync::mpsc::Receiver<String>, ::acquire::Acquire) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::acquire::Acquire::new(socket))
    }
}
<commit_msg>[acquire] Implement Into<Decimation> for SamplingRate<commit_after>use Module;
use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Gain {
    LV,
    HV,
}

impl ::std::convert::Into<String> for Gain {
    fn into(self) -> String {
        let s = match self {
            Gain::LV => "LV",
            Gain::HV => "HV",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for Gain {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "LV" => Ok(Gain::LV),
            "HV" => Ok(Gain::HV),
            gain => Err(format!("Unknow gain '{}'", gain)),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Source {
    IN1,
    IN2,
}

impl ::std::convert::Into<String> for Source {
    fn into(self) -> String {
        let s = match self {
            Source::IN1 => "SOUR1",
            Source::IN2 => "SOUR2",
        };

        String::from(s)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Decimation {
    DEC_1,
    DEC_8,
    DEC_64,
    DEC_1024,
    DEC_8192,
    DEC_65536,
}

impl ::std::convert::Into<String> for Decimation {
    fn into(self) -> String {
        let s = match self {
            Decimation::DEC_1 => "1",
            Decimation::DEC_8 => "8",
            Decimation::DEC_64 => "64",
            Decimation::DEC_1024 => "1024",
            Decimation::DEC_8192 => "8192",
            Decimation::DEC_65536 => "65536",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for Decimation {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "1" => Ok(Decimation::DEC_1),
            "8" => Ok(Decimation::DEC_8),
            "64" => Ok(Decimation::DEC_64),
            "1024" => Ok(Decimation::DEC_1024),
            "8192" => Ok(Decimation::DEC_8192),
            "65536" => Ok(Decimation::DEC_65536),
            decimation => Err(format!("Unknow decimation '{}'", decimation)),
        }
    }
}

impl ::std::convert::Into<SamplingRate> for Decimation {
    fn into(self) -> SamplingRate {
        match self {
            Decimation::DEC_1 => SamplingRate::RATE_125MHz,
            Decimation::DEC_8 => SamplingRate::RATE_15_6MHz,
            Decimation::DEC_64 => SamplingRate::RATE_1_9MHz,
            Decimation::DEC_1024 => SamplingRate::RATE_103_8kHz,
            Decimation::DEC_8192 => SamplingRate::RATE_15_2kHz,
            Decimation::DEC_65536 => SamplingRate::RATE_1_9kHz,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SamplingRate {
    RATE_125MHz,
    RATE_15_6MHz,
    RATE_1_9MHz,
    RATE_103_8kHz,
    RATE_15_2kHz,
    RATE_1_9kHz,
}

impl SamplingRate {
    pub fn get_buffer_duration(self) -> ::std::time::Duration {
        let (s, ns) = match self {
            SamplingRate::RATE_125MHz => (0, 131_072),
            SamplingRate::RATE_15_6MHz => (0, 1_049_000),
            SamplingRate::RATE_1_9MHz => (0, 8_389_000),
            SamplingRate::RATE_103_8kHz => (0, 134_218_000),
            SamplingRate::RATE_15_2kHz => (1, 740_000_000),
            SamplingRate::RATE_1_9kHz => (8, 590_000_000),
        };

        ::std::time::Duration::new(s, ns)
    }
}

impl ::std::fmt::Display for SamplingRate {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &SamplingRate::RATE_125MHz => "125 MHz",
            &SamplingRate::RATE_15_6MHz => "15.6 MHz",
            &SamplingRate::RATE_1_9MHz => "1.9 MHz",
            &SamplingRate::RATE_103_8kHz => "103.8 kHz",
            &SamplingRate::RATE_15_2kHz => "15.2 kHz",
            &SamplingRate::RATE_1_9kHz => "1.9 kHz",
        };

        write!(f, "{}", display)
    }
}

impl ::std::convert::Into<Decimation> for SamplingRate {
    fn into(self) -> Decimation {
        match self {
            SamplingRate::RATE_125MHz => Decimation::DEC_1,
            SamplingRate::RATE_15_6MHz => Decimation::DEC_8,
            SamplingRate::RATE_1_9MHz => Decimation::DEC_64,
            SamplingRate::RATE_103_8kHz => Decimation::DEC_1024,
            SamplingRate::RATE_15_2kHz => Decimation::DEC_8192,
            SamplingRate::RATE_1_9kHz => Decimation::DEC_65536,
        }
    }
}

impl ::std::convert::Into<String> for SamplingRate {
    fn into(self) -> String {
        let s = match self {
            SamplingRate::RATE_125MHz => "125MHz",
            SamplingRate::RATE_15_6MHz => "15_6MHz",
            SamplingRate::RATE_1_9MHz => "1_9MHz",
            SamplingRate::RATE_103_8kHz => "103_8kHz",
            SamplingRate::RATE_15_2kHz => "15_2kHz",
            SamplingRate::RATE_1_9kHz => "1_9kHz",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for SamplingRate {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "125000000 Hz" => Ok(SamplingRate::RATE_125MHz),
            "15600000 Hz" => Ok(SamplingRate::RATE_15_6MHz),
            "1900000 Hz" => Ok(SamplingRate::RATE_1_9MHz),
            "103800 Hz" => Ok(SamplingRate::RATE_103_8kHz),
            "15200 Hz" => Ok(SamplingRate::RATE_15_2kHz),
            "1900 Hz" => Ok(SamplingRate::RATE_1_9kHz),
            rate => Err(format!("Unknow sampling rate {}", rate)),
        }
    }
}

#[derive(Clone)]
pub struct Acquire {
    socket: ::std::cell::RefCell<Socket>,
    started: bool,
}

impl ::Module for Acquire {
    fn get_socket<'a>(&'a self) -> ::std::cell::RefMut<'a, ::socket::Socket> {
        self.socket.borrow_mut()
    }
}

impl Acquire {
    pub fn new(socket: Socket) -> Self {
        Acquire {
            socket: ::std::cell::RefCell::new(socket),
            started: false,
        }
    }

    /**
     * Starts acquisition.
     */
    pub fn start(&mut self) {
        self.send("ACQ:START");
        self.started = true;
    }

    /**
     * Stops acquisition.
     */
    pub fn stop(&mut self) {
        self.send("ACQ:STOP");
        self.started = false;
    }

    pub fn is_started(&self) -> bool {
        self.started
    }

    /**
     * Stops acquisition and sets all parameters to default values.
     */
    pub fn reset(&self) {
        self.send("ACQ:RST");
    }

    /**
     * Set decimation factor.
     */
    pub fn set_decimation(&self, decimation: Decimation) {
        self.send(format!("ACQ:DEC {}", Into::<String>::into(decimation)));
    }

    /**
     * Get decimation factor.
     */
    pub fn get_decimation(&self) -> Result<Decimation, String> {
        self.send("ACQ:DEC?");

        self.receive()
            .parse()
    }

    /**
     * Get sampling rate.
     *
     * # Panics
     *
     * Calling this command makes buffer overflow.
     * See https://github.com/RedPitaya/RedPitaya/pull/110
     */
    pub fn get_sampling_rate(&self) -> Result<SamplingRate, String> {
        self.send("ACQ:SRAT?");

        self.receive()
            .parse()
    }

    /**
     * Enable averaging.
     */
    pub fn enable_average(&self) {
        self.send("ACQ:AVG ON");
    }

    /**
     * Disable averaging.
     */
    pub fn disable_average(&self) {
        self.send("ACQ:AVG OFF");
    }

    /**
     * Get averaging status.
     */
    pub fn is_average_enabled(&self) -> bool {
        self.send("ACQ:AVG?");

        let message = self.receive();

        match message.as_str() {
            "ON" => true,
            _ => false,
        }
    }

    /**
     * Set gain settings to HIGH or LOW.
     *
     * This gain is referring to jumper settings on Red Pitaya fast analog inputs.
     */
    pub fn set_gain(&self, source: Source, gain: Gain) {
        self.send(format!("ACQ:{}:GAIN {}", Into::<String>::into(source), Into::<String>::into(gain)));
    }

    /**
     * Get gain settings to HIGH or LOW.
     */
    pub fn get_gain(&self, source: Source) -> Result<Gain, String> {
        self.send(format!("ACQ:{}:GAIN?", Into::<String>::into(source)));

        self.receive()
            .parse()
    }
}

#[cfg(test)]
mod test {
    macro_rules! acquire_assert {
        ($f:ident, $e:expr) => {
            let (rx, acquire) = create_acquire();

            acquire.$f();
            assert_eq!($e, rx.recv().unwrap());
        }
    }

    #[test]
    fn test_sampling_rate_get_buffer_duration() {
        let duration = ::std::time::Duration::new(8, 590_000_000);

        assert_eq!(duration, ::acquire::SamplingRate::RATE_1_9kHz.get_buffer_duration());
    }

    #[test]
    fn test_start() {
        let (rx, mut acquire) = create_acquire();

        acquire.start();
        assert_eq!("ACQ:START\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_stop() {
        let (rx, mut acquire) = create_acquire();

        acquire.stop();
        assert_eq!("ACQ:STOP\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_is_started() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.is_started(), false);
        acquire.start();
        assert_eq!(acquire.is_started(), true);
        acquire.stop();
        assert_eq!(acquire.is_started(), false);
    }

    #[test]
    fn test_reset() {
        acquire_assert!(reset, "ACQ:RST\r\n");
    }

    #[test]
    fn test_set_decimation() {
        let (rx, acquire) = create_acquire();

        acquire.set_decimation(::acquire::Decimation::DEC_8);
        assert_eq!("ACQ:DEC 8\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_decimation() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.get_decimation(), Ok(::acquire::Decimation::DEC_1));
    }

    #[test]
    fn test_get_sampling_rate() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.get_sampling_rate(), Ok(::acquire::SamplingRate::RATE_125MHz));
    }

    #[test]
    fn test_enable_average() {
        acquire_assert!(enable_average, "ACQ:AVG ON\r\n");
    }

    #[test]
    fn test_disable_average() {
        acquire_assert!(disable_average, "ACQ:AVG OFF\r\n");
    }

    #[test]
    fn test_is_average_enabled() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.is_average_enabled(), true);
    }

    #[test]
    fn test_set_gain() {
        let (rx, acquire) = create_acquire();

        acquire.set_gain(::acquire::Source::IN1, ::acquire::Gain::LV);
        assert_eq!("ACQ:SOUR1:GAIN LV\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_gain() {
        let (_, acquire) = create_acquire();

        assert_eq!(acquire.get_gain(::acquire::Source::IN1), Ok(::acquire::Gain::HV));
    }

    fn create_acquire() -> (::std::sync::mpsc::Receiver<String>, ::acquire::Acquire) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::acquire::Acquire::new(socket))
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_must_use, unused_variables, dead_code)]

extern crate combine;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::str;
use std::collections::HashMap;
use std::marker::PhantomData;
use combine::{spaces, parser, between, many, many1, digit, char, any, string, token, Parser, ParserExt, ParseError};
use combine::primitives::{State, Stream, ParseResult, Consumed};
use combine::combinator::{Between, Token, FnParser, satisfy};

//my own bencode stuff!
//
fn open_file <P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut fd = File::open(path).unwrap();
    let mut buffer:Vec<u8> = Vec::new();
    fd.read_to_end(&mut buffer);
    buffer
}

#[derive(Debug, Eq, PartialEq)]
enum Bencode {
    Int(i64),
    String(String),
    List(Vec<Bencode>),
    Dict(HashMap<String, Bencode>)
}

fn bencode_integer<I>(input: State<I>) -> ParseResult<i64, I> where I:Stream<Item=char> {
    let (open, close) = (char('i'), char('e'));
    let mut int = between(open, close, many1::<String, _>(digit())).map(|x| {
        x.parse::<i64>().unwrap()
    });
    int.parse_state(input)
}

fn bencode_string<I>(input: State<I>) -> ParseResult<String, I> where I:Stream<Item=char> {
    let (len, input_) = try!(bencode_string_length_prefix(input));
    input_.combine(|input__| take(len).parse_state(input__))
}

fn bencode_string_length_prefix<I>(input: State<I>) -> ParseResult<i32, I> where I:Stream<Item=char> {
    let many_digit = many1::<String, _>(digit());
    let mut get_len = (many_digit, char(':')).map(|(length, _)| length.parse::<i32>().unwrap());
    get_len.parse_state(input)
}

fn bencode_list<I>(input: State<I>) -> ParseResult<Vec<Bencode>, I> where I:Stream<Item=char> {
    let (open, close) = (char('l'), char('e'));
    let list_contents = many::<Vec<Bencode>, _>(bencode_any());
    let mut list = between(open, close, list_contents);
    list.parse_state(input)
}

fn bencode_dict<I>(input: State<I>) -> ParseResult<HashMap<String, Bencode>, I> where I:Stream<Item=char> {
    let (open, close) = (char('d'), char('e'));
    let pairs = (parser(bencode_string), bencode_any());
    let mut dict = between(open, close, many(pairs)).map(|entries:Vec<(String, Bencode)>|{
        let mut hash_map = HashMap::new();
        for (k, v) in entries {
            hash_map.insert(k, v);
        }
        hash_map
    });
    dict.parse_state(input)
}

fn bencode_any<I>() -> FnParser<I, fn (State<I>) -> ParseResult<Bencode, I>> where I:Stream<Item=char> {
    fn bencode_any_<I>(input: State<I>) -> ParseResult<Bencode, I> where I: Stream<Item=char> {
        parser(bencode_integer).map(Bencode::Int)
            .or(parser(bencode_string).map(Bencode::String))
            .or(parser(bencode_list).map(Bencode::List))
            .or(parser(bencode_dict).map(Bencode::Dict)).parse_state(input)
    }
    parser(bencode_any_)
}

fn take <I> (num: i32) -> SizedBuffer<I> where I: Stream<Item=char> {
    SizedBuffer(num, PhantomData)
}

#[derive(Clone)]
pub struct SizedBuffer <I>(i32, PhantomData<I>);
impl <I> Parser for SizedBuffer<I> where I: Stream<Item=char> {
    type Input = I;
    type Output = String;
    fn parse_lazy(&mut self, mut input: State<I>) -> ParseResult<String, I> {
        let start = input.position;
        let mut vec_buf:Vec<char> = Vec::new();
        for _ in 0..self.0 {
            match input.uncons() {
                Ok((other, rest)) => {
                    vec_buf.push(other);
                    input = rest.into_inner();
                }
                Err(error) => {
                    return error.combine(|mut error| {
                        error.position = start;
                        Err(Consumed::Consumed(error))
                    })
                }
            };
        }
        Ok((vec_buf.into_iter().collect(), Consumed::Consumed(input)))
    }
}

fn main () {
    let file_contents = open_file("t-test.torrent");

    match str::from_utf8(&file_contents) {
        Ok(v) => println!("file: {}", v),
        Err(e) => panic!("Not a UTF-8 String: {}", e)
    };

    let result = parser(bencode_dict).parse("d3:abci4ee");
}

#[test]
fn test_integer() {
    let result = parser(bencode_integer).parse("i57e");
    assert_eq!(result, Ok((57,"")));
}

#[test]
fn test_string() {
    let result = parser(bencode_string).parse("5:abcde");
    assert_eq!(result, Ok(("abcde".to_string(), "")));;
}

#[test]
fn test_list() {
    let homogenous_int_list = parser(bencode_list).parse("li57ei32ee");
    assert_eq!(homogenous_int_list, Ok((vec![Bencode::Int(57), Bencode::Int(32)], "")));

    let homogenous_str_list = parser(bencode_list).parse("l3:abc5:defghe");
    assert_eq!(homogenous_str_list, Ok((vec![Bencode::String("abc".to_string()), Bencode::String("defgh".to_string())], "")));

    let hetero_list = parser(bencode_list).parse("li32e3:abce");
    assert_eq!(hetero_list, Ok((vec![Bencode::Int(32), Bencode::String("abc".to_string())], "")));
}

#[test]
fn test_dict() {

}
<commit_msg>many(bencode_any())<commit_after>#![allow(unused_imports, unused_must_use, unused_variables, dead_code)]

extern crate combine;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::str;
use std::collections::HashMap;
use std::marker::PhantomData;
use combine::{spaces, parser, between, many, many1, digit, char, any, string, token, Parser, ParserExt, ParseError};
use combine::primitives::{State, Stream, ParseResult, Consumed};
use combine::combinator::{Between, Token, FnParser, satisfy};

//my own bencode stuff!
//
fn open_file <P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut fd = File::open(path).unwrap();
    let mut buffer:Vec<u8> = Vec::new();
    fd.read_to_end(&mut buffer);
    buffer
}

#[derive(Debug, Eq, PartialEq)]
enum Bencode {
    Int(i64),
    String(String),
    List(Vec<Bencode>),
    Dict(HashMap<String, Bencode>)
}

fn bencode_integer<I>(input: State<I>) -> ParseResult<i64, I> where I: Stream<Item=char> {
    let (open, close) = (char('i'), char('e'));
    let mut int = between(open, close, many1::<String, _>(digit())).map(|x| {
        x.parse::<i64>().unwrap()
    });
    int.parse_state(input)
}

fn bencode_string<I>(input: State<I>) -> ParseResult<String, I> where I: Stream<Item=char> {
    let (len, input_) = try!(bencode_string_length_prefix(input));
    input_.combine(|input__| take(len).parse_state(input__))
}

fn bencode_string_length_prefix<I>(input: State<I>) -> ParseResult<i32, I> where I:Stream<Item=char> {
    let many_digit = many1::<String, _>(digit());
    let mut get_len = (many_digit, char(':')).map(|(length, _)| length.parse::<i32>().unwrap());
    get_len.parse_state(input)
}

fn bencode_list<I>(input: State<I>) -> ParseResult<Vec<Bencode>, I> where I: Stream<Item=char> {
    let (open, close) = (char('l'), char('e'));
    let list_contents = many::<Vec<Bencode>, _>(bencode_any());
    let mut list = between(open, close, list_contents);
    list.parse_state(input)
}

fn bencode_dict<I>(input: State<I>) -> ParseResult<HashMap<String, Bencode>, I> where I: Stream<Item=char> {
    let (open, close) = (char('d'), char('e'));
    let pairs = (parser(bencode_string), bencode_any());
    let mut dict = between(open, close, many(pairs)).map(|entries:Vec<(String, Bencode)>|{
        let mut hash_map = HashMap::new();
        for (k, v) in entries {
            hash_map.insert(k, v);
        }
        hash_map
    });
    dict.parse_state(input)
}

fn bencode_any<I>() -> FnParser<I, fn (State<I>) -> ParseResult<Bencode, I>> where I: Stream<Item=char> {
    fn bencode_any_<I>(input: State<I>) -> ParseResult<Bencode, I> where I: Stream<Item=char> {
        parser(bencode_integer).map(Bencode::Int)
            .or(parser(bencode_string).map(Bencode::String))
            .or(parser(bencode_list).map(Bencode::List))
            .or(parser(bencode_dict).map(Bencode::Dict)).parse_state(input)
    }
    parser(bencode_any_)
}

fn take <I> (num: i32) -> SizedBuffer<I> where I: Stream<Item=char> {
    SizedBuffer(num, PhantomData)
}

#[derive(Clone)]
pub struct SizedBuffer <I>(i32, PhantomData<I>);
impl <I> Parser for SizedBuffer<I> where I: Stream<Item=char> {
    type Input = I;
    type Output = String;
    fn parse_lazy(&mut self, mut input: State<I>) -> ParseResult<String, I> {
        let start = input.position;
        let mut vec_buf:Vec<char> = Vec::new();
        for _ in 0..self.0 {
            match input.uncons() {
                Ok((other, rest)) => {
                    vec_buf.push(other);
                    input = rest.into_inner();
                }
                Err(error) => {
                    return error.combine(|mut error| {
                        error.position = start;
                        Err(Consumed::Consumed(error))
                    })
                }
            };
        }
        Ok((vec_buf.into_iter().collect(), Consumed::Consumed(input)))
    }
}

fn main () {
    let file_contents = open_file("t-test.torrent");
    match str::from_utf8(&file_contents) {
        Ok(v) => {
            let (result, _) = many::<Vec<Bencode>, _>(bencode_any()).parse(v).unwrap();
            println!("res: {:?}", result);
            println!("file: {}", v)
        },
        Err(e) => panic!("Not a UTF-8 String: {}", e)
    };
}

#[test]
fn test_integer() {
    let result = parser(bencode_integer).parse("i57e");
    assert_eq!(result, Ok((57,"")));
}

#[test]
fn test_string() {
    let result = parser(bencode_string).parse("5:abcde");
    assert_eq!(result, Ok(("abcde".to_string(), "")));;
}

#[test]
fn test_list() {
    let homogenous_int_list = parser(bencode_list).parse("li57ei32ee");
    assert_eq!(homogenous_int_list, Ok((vec![Bencode::Int(57), Bencode::Int(32)], "")));

    let homogenous_str_list = parser(bencode_list).parse("l3:abc5:defghe");
    assert_eq!(homogenous_str_list, Ok((vec![Bencode::String("abc".to_string()), Bencode::String("defgh".to_string())], "")));

    let hetero_list = parser(bencode_list).parse("li32e3:abce");
    assert_eq!(hetero_list, Ok((vec![Bencode::Int(32), Bencode::String("abc".to_string())], "")));
}

#[test]
fn test_dict() {
    let (dict_result, _) = parser(bencode_dict).parse("d3:abci4e4:andyli5eee").unwrap();
    assert_eq!(*dict_result.get("abc").unwrap(), Bencode::Int(4));
    assert_eq!(*dict_result.get("andy").unwrap(), Bencode::List(vec![Bencode::Int(5)]));
    assert_eq!(dict_result.len(), 2);
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::INTERNAL_METADATA_DIRECTIVE;
use common::{Diagnostic, DiagnosticsResult, NamedItem, WithLocation};
use graphql_ir::{
    Argument, ConstantArgument, ConstantValue, Directive, OperationDefinition, Program,
    Transformed, Transformer, ValidationMessage, Value,
};
use graphql_syntax::OperationKind;
use interner::{Intern, StringKey};
use lazy_static::lazy_static;

lazy_static! {
    pub static ref LIVE_QUERY_DIRECTIVE_NAME: StringKey = "live_query".intern();
    pub static ref LIVE_METADATA_KEY: StringKey = "live".intern();
    pub static ref PRELOADABLE_METADATA_KEY: StringKey = "relayPreloadable".intern();
    pub static ref POLLING_INTERVAL_ARG: StringKey = "polling_interval".intern();
    pub static ref CONFIG_ID_ARG: StringKey = "config_id".intern();
}

pub fn generate_live_query_metadata(program: &Program) -> DiagnosticsResult<Program> {
    let mut transformer = GenerateLiveQueryMetadata::new(program);
    let next_program = transformer
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transformer.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transformer.errors)
    }
}

struct GenerateLiveQueryMetadata<'s> {
    pub program: &'s Program,
    pub errors: Vec<Diagnostic>,
}

impl<'s> GenerateLiveQueryMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateLiveQueryMetadata {
            program,
            errors: vec![],
        }
    }
}

impl<'s> Transformer for GenerateLiveQueryMetadata<'s> {
    const NAME: &'static str = "GenerateLiveQueryMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        match operation.kind {
            OperationKind::Query => {
                let live_query_directive = operation.directives.named(*LIVE_QUERY_DIRECTIVE_NAME);

                if let Some(live_query_directive) = live_query_directive {
                    let polling_interval =
                        live_query_directive.arguments.named(*POLLING_INTERVAL_ARG);
                    let config_id = live_query_directive.arguments.named(*CONFIG_ID_ARG);

                    if polling_interval.is_none() && config_id.is_none() {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::LiveQueryTransformMissingConfig {
                                query_name: operation.name.item,
                            },
                            live_query_directive.name.location,
                        ));
                        return Transformed::Keep;
                    }

                    let mut next_directives = operation.directives.clone();

                    // I'm porting JS logic here. Not sure if the case where
                    // polling_interval and config_id both provided handled correctly
                    if let Some(polling_interval) = polling_interval {
                        let poll_interval_value = match polling_interval.value.item {
                            Value::Constant(ConstantValue::Int(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidPollingInterval {
                                        query_name: operation.name.item,
                                    },
                                    polling_interval.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *POLLING_INTERVAL_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::Int(poll_interval_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    } else if let Some(config_id) = config_id {
                        let config_id_value = match config_id.value.item {
                            Value::Constant(ConstantValue::String(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidConfigId {
                                        query_name: operation.name.item,
                                    },
                                    config_id.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *CONFIG_ID_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::String(config_id_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    }

                    Transformed::Replace(OperationDefinition {
                        directives: next_directives,
                        ..operation.clone()
                    })
                } else {
                    Transformed::Keep
                }
            }
            _ => Transformed::Keep,
        }
    }
}
<commit_msg>re-use is_preloadable_operation<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::INTERNAL_METADATA_DIRECTIVE;
use common::{Diagnostic, DiagnosticsResult, NamedItem, WithLocation};
use graphql_ir::{
    Argument, ConstantArgument, ConstantValue, Directive, OperationDefinition, Program,
    Transformed, Transformer, ValidationMessage, Value,
};
use graphql_syntax::OperationKind;
use interner::{Intern, StringKey};
use lazy_static::lazy_static;

lazy_static! {
    pub static ref LIVE_QUERY_DIRECTIVE_NAME: StringKey = "live_query".intern();
    pub static ref LIVE_METADATA_KEY: StringKey = "live".intern();
    pub static ref POLLING_INTERVAL_ARG: StringKey = "polling_interval".intern();
    pub static ref CONFIG_ID_ARG: StringKey = "config_id".intern();
}

pub fn generate_live_query_metadata(program: &Program) -> DiagnosticsResult<Program> {
    let mut transformer = GenerateLiveQueryMetadata::new(program);
    let next_program = transformer
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transformer.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transformer.errors)
    }
}

struct GenerateLiveQueryMetadata<'s> {
    pub program: &'s Program,
    pub errors: Vec<Diagnostic>,
}

impl<'s> GenerateLiveQueryMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateLiveQueryMetadata {
            program,
            errors: vec![],
        }
    }
}

impl<'s> Transformer for GenerateLiveQueryMetadata<'s> {
    const NAME: &'static str = "GenerateLiveQueryMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        match operation.kind {
            OperationKind::Query => {
                let live_query_directive = operation.directives.named(*LIVE_QUERY_DIRECTIVE_NAME);

                if let Some(live_query_directive) = live_query_directive {
                    let polling_interval =
                        live_query_directive.arguments.named(*POLLING_INTERVAL_ARG);
                    let config_id = live_query_directive.arguments.named(*CONFIG_ID_ARG);

                    if polling_interval.is_none() && config_id.is_none() {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::LiveQueryTransformMissingConfig {
                                query_name: operation.name.item,
                            },
                            live_query_directive.name.location,
                        ));
                        return Transformed::Keep;
                    }

                    let mut next_directives = operation.directives.clone();

                    // I'm porting JS logic here. Not sure if the case where
                    // polling_interval and config_id both provided handled correctly
                    if let Some(polling_interval) = polling_interval {
                        let poll_interval_value = match polling_interval.value.item {
                            Value::Constant(ConstantValue::Int(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidPollingInterval {
                                        query_name: operation.name.item,
                                    },
                                    polling_interval.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *POLLING_INTERVAL_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::Int(poll_interval_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    } else if let Some(config_id) = config_id {
                        let config_id_value = match config_id.value.item {
                            Value::Constant(ConstantValue::String(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidConfigId {
                                        query_name: operation.name.item,
                                    },
                                    config_id.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *CONFIG_ID_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::String(config_id_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    }

                    Transformed::Replace(OperationDefinition {
                        directives: next_directives,
                        ..operation.clone()
                    })
                } else {
                    Transformed::Keep
                }
            }
            _ => Transformed::Keep,
        }
    }
}
<|endoftext|>


<commit_before>//! Minimal REPL

#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate docopt;
extern crate rustc_serialize;
extern crate term;
extern crate lea_compiler as compiler;
extern crate lea_parser as parser;
extern crate lea_vm as vm;

use parser::span::DummyTerm;
use compiler::{CompileConfig, FnData};
use vm::mem::DefaultGc;
use vm::error::VmResult;
use vm::function::FunctionProto;
use vm::value::Value;
use vm::vm::VM;

use std::io::{self, stdin, stderr, Write};

docopt!(Args derive Debug, "
The interactive Lea REPL

Usage:
    lea [ --help | --version ]

Options:
    -h, --help          Show this help.
    -v, --version       Show the version of the Lea package.
");

/// Opens a terminal that writes to stderr. If stderr couldn't be opened as a terminal, creates a
/// `DummyTerm` that writes to stderr instead.
fn stderr_term() -> Box<term::StderrTerminal> {
    term::stderr().unwrap_or_else(|| Box::new(DummyTerm(io::stderr())))
}

/// Compiles a piece of code. Prints all errors / warnings to stderr, using color if stderr is a
/// terminal.
fn compile(code: &str, filename: &str) -> io::Result<Option<FnData>> {
    let mut fmt_target = stderr_term();
    let fmt_target = &mut *fmt_target;

    match compiler::compile_str(code, filename, &CompileConfig::default()) {
        Err(e) => {
            try!(e.format(code, filename, fmt_target));
            Ok(None)
        },
        Ok(output) => {
            let warns = output.warns;
            if warns.len() > 0 {
                for w in warns {
                    try!(w.format(code, filename, fmt_target));
                }
            }

            Ok(Some(output.mainproto))
        }
    }
}

/// Creates a VM and GC and executes the given `FnData` object. Prints the returned value or the
/// error thrown.
fn run_fndata(main: FnData) {
    let mut gc = DefaultGc::default();
    let proto = FunctionProto::from_fndata(main, &mut gc);
    let mut vm = VM::with_env(gc, proto, Value::TNil);

    let ret: VmResult = vm.start();
    match ret {
        Ok(vals) => {
            let vals: Vec<String> = vals.into_iter().map(|val| format!("{:?}", val)).collect();
            println!("{}", vals.join("\t"));
        }
        Err(e) => {
            println!("{:?}", e);
        }
    }
}

fn repl() -> io::Result<()> {
    let mut input = String::new();
    let mut stdin = io::stdin();
    let mut stdout = io::stdout();

    loop {
        try!(write!(stdout, "> "));
        try!(stdout.flush());
        try!(stdin.read_line(&mut input));

        if let Some(fndata) = try!(compile(&input, "<repl>")) {
            run_fndata(fndata);
        }

        input.clear();
    }
}

#[allow(dead_code)]     // TODO write tests
fn main() {
    match Args::docopt().decode::<Args>() {
        Err(e) => {
            println!("{}", e);
        }
        Ok(args) => {
            match args {
                Args { flag_version: true, .. } => {
                    println!("Lea {}", option_env!("CARGO_PKG_VERSION").unwrap_or("<unknown version>"));
                }
                Args { .. } => {
                    match repl() {
                        Err(e) => println!("{}", e),
                        Ok(_) => unreachable!(),
                    }
                }
            }
        }
    }
}
<commit_msg>repl: use BufReader and don't print 0 results<commit_after>//! Minimal REPL

#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate docopt;
extern crate rustc_serialize;
extern crate term;
extern crate lea_compiler as compiler;
extern crate lea_parser as parser;
extern crate lea_vm as vm;

use parser::span::DummyTerm;
use compiler::{CompileConfig, FnData};
use vm::mem::DefaultGc;
use vm::error::VmResult;
use vm::function::FunctionProto;
use vm::value::Value;
use vm::vm::VM;

use std::io::{self, stdin, stderr, Write, BufRead};

docopt!(Args derive Debug, "
The interactive Lea REPL

Usage:
    lea [ --help | --version ]

Options:
    -h, --help          Show this help.
    -v, --version       Show the version of the Lea package.
");

/// Opens a terminal that writes to stderr. If stderr couldn't be opened as a terminal, creates a
/// `DummyTerm` that writes to stderr instead.
fn stderr_term() -> Box<term::StderrTerminal> {
    term::stderr().unwrap_or_else(|| Box::new(DummyTerm(io::stderr())))
}

/// Compiles a piece of code. Prints all errors / warnings to stderr, using color if stderr is a
/// terminal.
fn compile(code: &str, filename: &str) -> io::Result<Option<FnData>> {
    let mut fmt_target = stderr_term();
    let fmt_target = &mut *fmt_target;

    match compiler::compile_str(code, filename, &CompileConfig::default()) {
        Err(e) => {
            try!(e.format(code, filename, fmt_target));
            Ok(None)
        },
        Ok(output) => {
            let warns = output.warns;
            if warns.len() > 0 {
                for w in warns {
                    try!(w.format(code, filename, fmt_target));
                }
            }

            Ok(Some(output.mainproto))
        }
    }
}

/// Creates a VM and GC and executes the given `FnData` object. Prints the returned value or the
/// error thrown.
fn run_fndata(main: FnData) {
    let mut gc = DefaultGc::default();
    let proto = FunctionProto::from_fndata(main, &mut gc);
    let mut vm = VM::with_env(gc, proto, Value::TNil);

    let ret: VmResult = vm.start();
    match ret {
        Ok(vals) => {
            if !vals.is_empty() {
                let vals: Vec<String> = vals.into_iter().map(|val| format!("{:?}", val)).collect();
                println!("{}", vals.join("\t"));
            }
        }
        Err(e) => {
            println!("{:?}", e);
        }
    }
}

fn print_prompt() -> io::Result<()> {
    let mut stdout = io::stdout();
    try!(write!(stdout, "> "));
    try!(stdout.flush());

    Ok(())
}

fn repl() -> io::Result<()> {
    let stdin = io::stdin();
    let stdin = io::BufReader::new(stdin);

    try!(print_prompt());
    for input in stdin.lines() {
        let input = try!(input);
        if let Some(fndata) = try!(compile(&input, "<repl>")) {
            run_fndata(fndata);
        }

        try!(print_prompt());
    }

    Ok(())
}

#[allow(dead_code)]     // TODO write tests
fn main() {
    match Args::docopt().decode::<Args>() {
        Err(e) => {
            println!("{}", e);
        }
        Ok(args) => {
            match args {
                Args { flag_version: true, .. } => {
                    println!("Lea {}", option_env!("CARGO_PKG_VERSION").unwrap_or("<unknown version>"));
                }
                Args { .. } => {
                    match repl() {
                        Err(e) => println!("{}", e),
                        Ok(_) => unreachable!(),
                    }
                }
            }
        }
    }
}
<|endoftext|>