<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayoutSize};
use api::{FilterOp, LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
use api::{ItemRange, MixBlendMode, StackingContext};
use internal_types::FastHashMap;
use std::sync::Arc;

/// Stores a map of the animated property bindings for the current display list. These
/// can be used to animate the transform and/or opacity of a display list without
/// re-submitting the display list itself.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct SceneProperties {
    transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
    float_properties: FastHashMap<PropertyBindingId, f32>,
    current_properties: DynamicProperties,
    pending_properties: Option<DynamicProperties>,
}

impl SceneProperties {
    pub fn new() -> Self {
        SceneProperties {
            transform_properties: FastHashMap::default(),
            float_properties: FastHashMap::default(),
            current_properties: DynamicProperties::default(),
            pending_properties: None,
        }
    }

    /// Set the current property list for this display list.
    pub fn set_properties(&mut self, properties: DynamicProperties) {
        self.pending_properties = Some(properties);
    }

    /// Add to the current property list for this display list.
    pub fn add_properties(&mut self, properties: DynamicProperties) {
        let mut pending_properties = self.pending_properties
            .take()
            .unwrap_or_default();

        pending_properties.transforms.extend(properties.transforms);
        pending_properties.floats.extend(properties.floats);

        self.pending_properties = Some(pending_properties);
    }

    /// Flush any pending updates to the scene properties. Returns
    /// true if the properties have changed since the last flush
    /// was called. This code allows properties to be changed by
    /// multiple set_properties and add_properties calls during a
    /// single transaction, and still correctly determine if any
    /// properties have changed. This can have significant power
    /// saving implications, allowing a frame build to be skipped
    /// if the properties haven't changed in many cases.
    pub fn flush_pending_updates(&mut self) -> bool {
        let mut properties_changed = false;

        if let Some(pending_properties) = self.pending_properties.take() {
            if pending_properties != self.current_properties {
                self.transform_properties.clear();
                self.float_properties.clear();

                for property in &pending_properties.transforms {
                    self.transform_properties
                        .insert(property.key.id, property.value);
                }

                for property in &pending_properties.floats {
                    self.float_properties
                        .insert(property.key.id, property.value);
                }

                self.current_properties = pending_properties;
                properties_changed = true;
            }
        }

        properties_changed
    }

    /// Get the current value for a transform property.
    pub fn resolve_layout_transform(
        &self,
        property: &PropertyBinding<LayoutTransform>,
    ) -> LayoutTransform {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key, v) => {
                self.transform_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or(v)
            }
        }
    }

    /// Get the current value for a float property.
    pub fn resolve_float(
        &self,
        property: &PropertyBinding<f32>
    ) -> f32 {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key, v) => {
                self.float_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or(v)
            }
        }
    }
}

/// A representation of the layout within the display port for a given document or iframe.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct ScenePipeline {
    pub pipeline_id: PipelineId,
    pub viewport_size: LayoutSize,
    pub content_size: LayoutSize,
    pub background_color: Option<ColorF>,
    pub display_list: BuiltDisplayList,
}

/// A complete representation of the layout bundling visible pipelines together.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct Scene {
    pub root_pipeline_id: Option<PipelineId>,
    pub pipelines: FastHashMap<PipelineId, Arc<ScenePipeline>>,
    pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
}

impl Scene {
    pub fn new() -> Self {
        Scene {
            root_pipeline_id: None,
            pipelines: FastHashMap::default(),
            pipeline_epochs: FastHashMap::default(),
        }
    }

    pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
        self.root_pipeline_id = Some(pipeline_id);
    }

    pub fn get_display_list_for_pipeline(&self, pipeline_id: PipelineId) -> &BuiltDisplayList {
        &self.pipelines
            .get(&pipeline_id)
            .expect("Expected to find display list for pipeline")
            .display_list
    }

    pub fn set_display_list(
        &mut self,
        pipeline_id: PipelineId,
        epoch: Epoch,
        display_list: BuiltDisplayList,
        background_color: Option<ColorF>,
        viewport_size: LayoutSize,
        content_size: LayoutSize,
    ) {
        let new_pipeline = ScenePipeline {
            pipeline_id,
            viewport_size,
            content_size,
            background_color,
            display_list,
        };

        self.pipelines.insert(pipeline_id, Arc::new(new_pipeline));
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }

    pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
        if self.root_pipeline_id == Some(pipeline_id) {
            self.root_pipeline_id = None;
        }
        self.pipelines.remove(&pipeline_id);
        self.pipeline_epochs.remove(&pipeline_id);
    }

    pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }

    pub fn has_root_pipeline(&self) -> bool {
        if let Some(ref root_id) = self.root_pipeline_id {
            return self.pipelines.contains_key(root_id);
        }

        false
    }
}

/// An arbitrary number which we assume opacity is invisible below.
pub const OPACITY_EPSILON: f32 = 0.001;

pub trait FilterOpHelpers {
    fn is_visible(&self) -> bool;
    fn is_noop(&self) -> bool;
}

impl FilterOpHelpers for FilterOp {
    fn is_visible(&self) -> bool {
        match *self {
            FilterOp::Identity |
            FilterOp::Blur(..) |
            FilterOp::Brightness(..) |
            FilterOp::Contrast(..) |
            FilterOp::Grayscale(..) |
            FilterOp::HueRotate(..) |
            FilterOp::Invert(..) |
            FilterOp::Saturate(..) |
            FilterOp::Sepia(..) |
            FilterOp::DropShadow(..) |
            FilterOp::ColorMatrix(..) => true,
            FilterOp::Opacity(_, amount) => {
                amount > OPACITY_EPSILON
            }
        }
    }

    fn is_noop(&self) -> bool {
        match *self {
            FilterOp::Identity => false, // this is intentional
            FilterOp::Blur(length) => length == 0.0,
            FilterOp::Brightness(amount) => amount == 1.0,
            FilterOp::Contrast(amount) => amount == 1.0,
            FilterOp::Grayscale(amount) => amount == 0.0,
            FilterOp::HueRotate(amount) => amount == 0.0,
            FilterOp::Invert(amount) => amount == 0.0,
            FilterOp::Opacity(_, amount) => amount >= 1.0,
            FilterOp::Saturate(amount) => amount == 1.0,
            FilterOp::Sepia(amount) => amount == 0.0,
            FilterOp::DropShadow(offset, blur, _) => {
                offset.x == 0.0 && offset.y == 0.0 && blur == 0.0
            },
            FilterOp::ColorMatrix(matrix) => {
                matrix == [1.0, 0.0, 0.0, 0.0,
                           0.0, 1.0, 0.0, 0.0,
                           0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 1.0,
                           0.0, 0.0, 0.0, 0.0]
            }
        }
    }
}

pub trait StackingContextHelpers {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp>;
}

impl StackingContextHelpers for StackingContext {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
        match self.mix_blend_mode {
            MixBlendMode::Normal => None,
            _ => Some(self.mix_blend_mode),
        }
    }

    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp> {
        // TODO(gw): Now that we resolve these later on,
        //           we could probably make it a bit
        //           more efficient than cloning these here.
        let mut filters = vec![];
        for filter in display_list.get(input_filters) {
            filters.push(filter);
        }
        filters
    }
}
<commit_msg>Don't move pending_properties to current_properties in flush_pending_updates<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayoutSize};
use api::{FilterOp, LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
use api::{ItemRange, MixBlendMode, StackingContext};
use internal_types::FastHashMap;
use std::sync::Arc;

/// Stores a map of the animated property bindings for the current display list. These
/// can be used to animate the transform and/or opacity of a display list without
/// re-submitting the display list itself.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct SceneProperties {
    transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
    float_properties: FastHashMap<PropertyBindingId, f32>,
    current_properties: DynamicProperties,
    pending_properties: Option<DynamicProperties>,
}

impl SceneProperties {
    pub fn new() -> Self {
        SceneProperties {
            transform_properties: FastHashMap::default(),
            float_properties: FastHashMap::default(),
            current_properties: DynamicProperties::default(),
            pending_properties: None,
        }
    }

    /// Set the current property list for this display list.
    pub fn set_properties(&mut self, properties: DynamicProperties) {
        self.pending_properties = Some(properties);
    }

    /// Add to the current property list for this display list.
    pub fn add_properties(&mut self, properties: DynamicProperties) {
        let mut pending_properties = self.pending_properties
            .take()
            .unwrap_or_default();

        pending_properties.transforms.extend(properties.transforms);
        pending_properties.floats.extend(properties.floats);

        self.pending_properties = Some(pending_properties);
    }

    /// Flush any pending updates to the scene properties. Returns
    /// true if the properties have changed since the last flush
    /// was called. This code allows properties to be changed by
    /// multiple set_properties and add_properties calls during a
    /// single transaction, and still correctly determine if any
    /// properties have changed. This can have significant power
    /// saving implications, allowing a frame build to be skipped
    /// if the properties haven't changed in many cases.
    pub fn flush_pending_updates(&mut self) -> bool {
        let mut properties_changed = false;

        if let Some(ref pending_properties) = self.pending_properties {
            if *pending_properties != self.current_properties {
                self.transform_properties.clear();
                self.float_properties.clear();

                for property in &pending_properties.transforms {
                    self.transform_properties
                        .insert(property.key.id, property.value);
                }

                for property in &pending_properties.floats {
                    self.float_properties
                        .insert(property.key.id, property.value);
                }

                self.current_properties = pending_properties.clone();
                properties_changed = true;
            }
        }

        properties_changed
    }

    /// Get the current value for a transform property.
    pub fn resolve_layout_transform(
        &self,
        property: &PropertyBinding<LayoutTransform>,
    ) -> LayoutTransform {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key, v) => {
                self.transform_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or(v)
            }
        }
    }

    /// Get the current value for a float property.
    pub fn resolve_float(
        &self,
        property: &PropertyBinding<f32>
    ) -> f32 {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key, v) => {
                self.float_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or(v)
            }
        }
    }
}

/// A representation of the layout within the display port for a given document or iframe.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct ScenePipeline {
    pub pipeline_id: PipelineId,
    pub viewport_size: LayoutSize,
    pub content_size: LayoutSize,
    pub background_color: Option<ColorF>,
    pub display_list: BuiltDisplayList,
}

/// A complete representation of the layout bundling visible pipelines together.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct Scene {
    pub root_pipeline_id: Option<PipelineId>,
    pub pipelines: FastHashMap<PipelineId, Arc<ScenePipeline>>,
    pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
}

impl Scene {
    pub fn new() -> Self {
        Scene {
            root_pipeline_id: None,
            pipelines: FastHashMap::default(),
            pipeline_epochs: FastHashMap::default(),
        }
    }

    pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
        self.root_pipeline_id = Some(pipeline_id);
    }

    pub fn get_display_list_for_pipeline(&self, pipeline_id: PipelineId) -> &BuiltDisplayList {
        &self.pipelines
            .get(&pipeline_id)
            .expect("Expected to find display list for pipeline")
            .display_list
    }

    pub fn set_display_list(
        &mut self,
        pipeline_id: PipelineId,
        epoch: Epoch,
        display_list: BuiltDisplayList,
        background_color: Option<ColorF>,
        viewport_size: LayoutSize,
        content_size: LayoutSize,
    ) {
        let new_pipeline = ScenePipeline {
            pipeline_id,
            viewport_size,
            content_size,
            background_color,
            display_list,
        };

        self.pipelines.insert(pipeline_id, Arc::new(new_pipeline));
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }

    pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
        if self.root_pipeline_id == Some(pipeline_id) {
            self.root_pipeline_id = None;
        }
        self.pipelines.remove(&pipeline_id);
        self.pipeline_epochs.remove(&pipeline_id);
    }

    pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }

    pub fn has_root_pipeline(&self) -> bool {
        if let Some(ref root_id) = self.root_pipeline_id {
            return self.pipelines.contains_key(root_id);
        }

        false
    }
}

/// An arbitrary number which we assume opacity is invisible below.
pub const OPACITY_EPSILON: f32 = 0.001;

pub trait FilterOpHelpers {
    fn is_visible(&self) -> bool;
    fn is_noop(&self) -> bool;
}

impl FilterOpHelpers for FilterOp {
    fn is_visible(&self) -> bool {
        match *self {
            FilterOp::Identity |
            FilterOp::Blur(..) |
            FilterOp::Brightness(..) |
            FilterOp::Contrast(..) |
            FilterOp::Grayscale(..) |
            FilterOp::HueRotate(..) |
            FilterOp::Invert(..) |
            FilterOp::Saturate(..) |
            FilterOp::Sepia(..) |
            FilterOp::DropShadow(..) |
            FilterOp::ColorMatrix(..) => true,
            FilterOp::Opacity(_, amount) => {
                amount > OPACITY_EPSILON
            }
        }
    }

    fn is_noop(&self) -> bool {
        match *self {
            FilterOp::Identity => false, // this is intentional
            FilterOp::Blur(length) => length == 0.0,
            FilterOp::Brightness(amount) => amount == 1.0,
            FilterOp::Contrast(amount) => amount == 1.0,
            FilterOp::Grayscale(amount) => amount == 0.0,
            FilterOp::HueRotate(amount) => amount == 0.0,
            FilterOp::Invert(amount) => amount == 0.0,
            FilterOp::Opacity(_, amount) => amount >= 1.0,
            FilterOp::Saturate(amount) => amount == 1.0,
            FilterOp::Sepia(amount) => amount == 0.0,
            FilterOp::DropShadow(offset, blur, _) => {
                offset.x == 0.0 && offset.y == 0.0 && blur == 0.0
            },
            FilterOp::ColorMatrix(matrix) => {
                matrix == [1.0, 0.0, 0.0, 0.0,
                           0.0, 1.0, 0.0, 0.0,
                           0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 1.0,
                           0.0, 0.0, 0.0, 0.0]
            }
        }
    }
}

pub trait StackingContextHelpers {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp>;
}

impl StackingContextHelpers for StackingContext {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
        match self.mix_blend_mode {
            MixBlendMode::Normal => None,
            _ => Some(self.mix_blend_mode),
        }
    }

    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp> {
        // TODO(gw): Now that we resolve these later on,
        //           we could probably make it a bit
        //           more efficient than cloning these here.
        let mut filters = vec![];
        for filter in display_list.get(input_filters) {
            filters.push(filter);
        }
        filters
    }
}
<|endoftext|>


<commit_before>struct ABig👩👩👧👧Family; //~ ERROR identifiers cannot contain emojis
struct 👀; //~ ERROR identifiers cannot contain emojis
impl 👀 {
    fn full_of_✨() -> 👀 { //~ ERROR identifiers cannot contain emojis
        👀
    }
}
fn i_like_to_😅_a_lot() -> 👀 { //~ ERROR identifiers cannot contain emojis
    👀::full_of✨() //~ ERROR no function or associated item named `full_of✨` found for struct `👀`
    //~^ ERROR identifiers cannot contain emojis
}
fn main() {
    let _ = i_like_to_😄_a_lot(); //~ ERROR cannot find function `i_like_to_😄_a_lot` in this scope
    //~^ ERROR identifiers cannot contain emojis
}

<commit_msg>fix fmt<commit_after>struct ABig👩👩👧👧Family; //~ ERROR identifiers cannot contain emojis
struct 👀; //~ ERROR identifiers cannot contain emojis
impl 👀 {
    fn full_of_✨() -> 👀 { //~ ERROR identifiers cannot contain emojis
        👀
    }
}
fn i_like_to_😅_a_lot() -> 👀 { //~ ERROR identifiers cannot contain emojis
    👀::full_of✨() //~ ERROR no function or associated item named `full_of✨` found for struct `👀`
    //~^ ERROR identifiers cannot contain emojis
}
fn main() {
    let _ = i_like_to_😄_a_lot(); //~ ERROR cannot find function `i_like_to_😄_a_lot` in this scope
    //~^ ERROR identifiers cannot contain emojis
}
<|endoftext|>


<commit_before>use std::{collections::HashMap, sync::Arc};
use lightning::map::ObjectMap;

use dovahkiin::types::OwnedValue;

use crate::ram::chunk::Chunk;

pub mod sm;

pub struct SchemaStatistics {
  histogram: HashMap<u64, [OwnedValue; 10]>, // min and max is first and last
  count: usize
}

pub struct ChunkStatistics {
  schemas: ObjectMap<Arc<SchemaStatistics>>
}

impl ChunkStatistics {
  pub fn from_chunk(chunk: &Chunk) -> Self {
    // for (hash, ptr) in chunk.cell_index.entries() {

    // }
    unimplemented!()
  }
}<commit_msg>scaffolding statistics from chunk<commit_after>use std::{collections::HashMap, sync::Arc};
use itertools::Itertools;
use lightning::map::{Map, ObjectMap};

use dovahkiin::types::{OwnedValue, SharedValue};

use crate::ram::{cell::{CellHeader, header_from_chunk_raw, select_from_chunk_raw}, chunk::Chunk};

pub mod sm;

pub struct SchemaStatistics {
  histogram: HashMap<u64, [OwnedValue; 10]>, // min and max is first and last
  count: usize
}

pub struct ChunkStatistics {
  schemas: ObjectMap<Arc<SchemaStatistics>>
}

impl ChunkStatistics {
  pub fn from_chunk(chunk: &Chunk) -> Self {
    for (hash, _) in chunk.cell_index.entries() {
      let loc = if let Ok(ptr) = chunk.location_for_read(hash as u64) {
        ptr
      } else {
        trace!("Cannot obtain cell lock {} for statistics", hash);
        continue;
      };
      match header_from_chunk_raw(*loc) {
        Ok((header, _)) => {
          let schema_id = header.schema;
          if let Some(schema) = chunk.meta.schemas.get(&schema_id) {
            let fields = schema.index_fields.keys().cloned().collect_vec();
            if let Ok(partial_cell) = select_from_chunk_raw(*loc, chunk, fields.as_slice()) {
              drop(loc); // Release lock for the cell early
              let field_array = if fields.len() == 1 {
                vec![partial_cell]
              } else if let SharedValue::Array(arr) = partial_cell {
                arr
              } else {
                error!("Cannot decode partial cell for statistics {:?}", partial_cell);
                continue;
              };
              for (i, val) in field_array.into_iter().enumerate() {
                if val == SharedValue::Null || val == SharedValue::NA {
                  continue;
                }
                let field_id = fields[i];
                // TODO: build the histogram
              }
            }
          } else {
            warn!("Cannot get schema {} for statistics", schema_id);
          }
        },
        Err(e) => {
          warn!("Failed to read {} for statistics, error: {:?}", hash, e);
        }
      }
    }
    unimplemented!()
  }
}<|endoftext|>


<commit_before>use std::io;
use std::string::String;
use std::io::Write; // Used for flush implicitly?
use std::str;

struct Topping<'a> {
    name: &'a str,
    vegeterian: bool,
    price: f32
}

struct Pizza<'a> {
    toppings: Vec<Topping<'a>>,
    base: Base<'a>
}

struct Base<'a> {
    name: &'a str,
    height: f32,
    thickness: f32,
    vegeterian: bool
}

impl<'a> Pizza<'a> {
    pub fn to_string(&self) -> String {
        let total: f32 = self.toppings
            .iter()
            .map(|topping| topping.price)
            .fold(0f32, |left, right| { left + right });
        let topping_list = self.toppings.iter().map(|topping| topping.name).collect::<Vec<&str>>().join(", ");
        return format!("Pizza with {} has price {}", topping_list, total);
    }
}

fn main() {
    let stdin = io::stdin();
    let name = get_name(stdin);
    println!("Hello {}", name);
    str_topping(get_topping());
    println!("Pizza is {}", get_pizza().to_string());
}

fn get_pizza<'a>() -> Pizza<'a> {
    return Pizza { toppings: vec!(get_topping(), get_topping()), base: Base{vegeterian: false, name: "Test base", height: 12.5f32, thickness: 113f32}};
}

fn get_topping<'a>() -> Topping<'a> {
    return Topping { name: "Salami", price: 0.7, vegeterian: false}
}

fn str_topping(topping: Topping) {
    println!("{} - {}", topping.name, topping.price)
}

fn get_name(stdin: io::Stdin) -> String {
    print!("Enter name: ");
    io::stdout().flush();
    let mut name = String::new();
    stdin.read_line(&mut name);
    return name;
}
<commit_msg>Added vegeterian funciton to pizza<commit_after>use std::io;
use std::string::String;
use std::io::Write; // Used for flush implicitly?
use std::str;

struct Topping<'a> {
    name: &'a str,
    vegetarian: bool,
    price: f32
}

struct Pizza<'a> {
    toppings: Vec<Topping<'a>>,
    base: Base<'a>
}

struct Base<'a> {
    name: &'a str,
    height: f32,
    thickness: f32,
    vegetarian: bool
}

impl<'a> Pizza<'a> {
    pub fn to_string(&self) -> String {
        let total: f32 = self.toppings
            .iter()
            .map(|topping| topping.price)
            .fold(0f32, |left, right| { left + right });
        let topping_list = self.toppings
            .iter()
            .map(|topping| topping.name)
            .collect::<Vec<&str>>()
            .join(", ");
        return format!("Pizza with {} has price {} and is {}vegetarian", topping_list, total, if self.is_vegetarian() {""} else {"not "});
    }

    pub fn is_vegetarian(&self) -> bool {
        let veg_toppings = self.toppings
            .iter()
            .map(|topping| topping.vegetarian)
            .fold(false, |left, right| {left || right});
        return veg_toppings || self.base.vegetarian;
    }
}

fn main() {
    let stdin = io::stdin();
    let name = get_name(stdin);
    println!("Hello {}", name);
    str_topping(get_topping());
    println!("Pizza is {}", get_pizza().to_string());
}

fn get_pizza<'a>() -> Pizza<'a> {
    return Pizza { toppings: vec!(get_topping(), get_topping()), base: Base{ vegetarian: false, name: "Test base", height: 12.5f32, thickness: 113f32}};
}

fn get_topping<'a>() -> Topping<'a> {
    return Topping { name: "Salami", price: 0.7, vegetarian: false}
}

fn str_topping(topping: Topping) {
    println!("{} - {}", topping.name, topping.price)
}

fn get_name(stdin: io::Stdin) -> String {
    print!("Enter name: ");
    io::stdout().flush();
    let mut name = String::new();
    stdin.read_line(&mut name);
    return name;
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{adapter::Adapter, FileHandle, ReadRecordBytes};
use anyhow::Result;
use bytes::Bytes;
use futures::{stream, stream::TryStreamExt};
use libra_crypto::HashValue;
use libra_types::{account_state_blob::AccountStateBlob, transaction::Version};
use tokio::io::{AsyncRead, AsyncReadExt};
use tokio_util::compat::FuturesAsyncReadCompatExt;

pub struct BackupServiceClient {
    port: u16,
    client: reqwest::Client,
}

impl BackupServiceClient {
    pub fn new(port: u16) -> Self {
        Self {
            port,
            client: reqwest::Client::new(),
        }
    }

    async fn get(&self, path: &str) -> Result<impl AsyncRead> {
        Ok(self
            .client
            .get(&format!("http://localhost:{}/{}", self.port, path))
            .send()
            .await?
            .error_for_status()?
            .bytes_stream()
            .map_err(|e| futures::io::Error::new(futures::io::ErrorKind::Other, e))
            .into_async_read()
            .compat())
    }

    pub async fn get_latest_state_root(&self) -> Result<(Version, HashValue)> {
        let mut buf = Vec::new();
        self.get("latest_state_root")
            .await?
            .read_to_end(&mut buf)
            .await?;
        Ok(lcs::from_bytes(&buf)?)
    }

    async fn get_account_range_proof(
        &self,
        key: HashValue,
        version: Version,
    ) -> Result<impl AsyncRead> {
        self.get(&format!("state_range_proof/{}/{:x}", version, key))
            .await
    }

    async fn get_state_snapshot(&self, version: Version) -> Result<impl AsyncRead> {
        self.get(&format!("state_snapshot/{}", version)).await
    }
}

pub async fn backup_account_state(
    client: &BackupServiceClient,
    version: Version,
    adapter: &impl Adapter,
    max_chunk_size: usize,
) -> Result<Vec<(FileHandle, FileHandle)>> {
    let mut chunk = vec![];
    let mut ret = vec![];

    let mut state_snapshot_stream = client.get_state_snapshot(version).await?;
    let mut prev_record_bytes: Option<Bytes> = None;
    while let Some(record_bytes) = state_snapshot_stream.read_record_bytes().await? {
        if chunk.len() + 4 + record_bytes.len() > max_chunk_size {
            assert!(chunk.len() <= max_chunk_size);
            let account_state_file = adapter
                .write_new_file(stream::once(async move { chunk }))
                .await?;

            let prb =
                prev_record_bytes.expect("max_chunk_size should be larger than account size.");
            let (prev_key, _): (HashValue, AccountStateBlob) = lcs::from_bytes(&prb)?;
            println!(
                "Reached max_chunk_size. Asking proof for key: {:?}",
                prev_key,
            );
            let proof_file = get_proof_and_write(client, adapter, prev_key, version).await?;
            ret.push((account_state_file, proof_file));
            chunk = vec![];
        }

        chunk.extend(&(record_bytes.len() as u32).to_be_bytes());
        chunk.extend(&record_bytes);
        prev_record_bytes = Some(record_bytes);
    }

    assert!(!chunk.is_empty());
    assert!(chunk.len() <= max_chunk_size);
    let account_state_file = adapter
        .write_new_file(stream::once(async move { chunk }))
        .await?;

    let prb = prev_record_bytes.expect("Should have at least one account.");
    let (prev_key, _): (HashValue, AccountStateBlob) = lcs::from_bytes(&prb)?;
    println!("Asking proof for last key: {:x}", prev_key);
    let proof_file = get_proof_and_write(client, adapter, prev_key, version).await?;
    ret.push((account_state_file, proof_file));

    Ok(ret)
}

async fn get_proof_and_write(
    client: &BackupServiceClient,
    adapter: &impl Adapter,
    key: HashValue,
    version: Version,
) -> Result<FileHandle> {
    let mut proof_bytes = Vec::new();
    client
        .get_account_range_proof(key, version)
        .await?
        .read_to_end(&mut proof_bytes)
        .await?;
    let file = adapter
        .write_new_file(stream::once(async move { proof_bytes }))
        .await?;
    Ok(file)
}
<commit_msg>[backup] trivial: remove magic number 4<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{adapter::Adapter, FileHandle, ReadRecordBytes};
use anyhow::Result;
use bytes::Bytes;
use futures::{stream, stream::TryStreamExt};
use libra_crypto::HashValue;
use libra_types::{account_state_blob::AccountStateBlob, transaction::Version};
use std::mem::size_of;
use tokio::io::{AsyncRead, AsyncReadExt};
use tokio_util::compat::FuturesAsyncReadCompatExt;

pub struct BackupServiceClient {
    port: u16,
    client: reqwest::Client,
}

impl BackupServiceClient {
    pub fn new(port: u16) -> Self {
        Self {
            port,
            client: reqwest::Client::new(),
        }
    }

    async fn get(&self, path: &str) -> Result<impl AsyncRead> {
        Ok(self
            .client
            .get(&format!("http://localhost:{}/{}", self.port, path))
            .send()
            .await?
            .error_for_status()?
            .bytes_stream()
            .map_err(|e| futures::io::Error::new(futures::io::ErrorKind::Other, e))
            .into_async_read()
            .compat())
    }

    pub async fn get_latest_state_root(&self) -> Result<(Version, HashValue)> {
        let mut buf = Vec::new();
        self.get("latest_state_root")
            .await?
            .read_to_end(&mut buf)
            .await?;
        Ok(lcs::from_bytes(&buf)?)
    }

    async fn get_account_range_proof(
        &self,
        key: HashValue,
        version: Version,
    ) -> Result<impl AsyncRead> {
        self.get(&format!("state_range_proof/{}/{:x}", version, key))
            .await
    }

    async fn get_state_snapshot(&self, version: Version) -> Result<impl AsyncRead> {
        self.get(&format!("state_snapshot/{}", version)).await
    }
}

pub async fn backup_account_state(
    client: &BackupServiceClient,
    version: Version,
    adapter: &impl Adapter,
    max_chunk_size: usize,
) -> Result<Vec<(FileHandle, FileHandle)>> {
    let mut chunk = vec![];
    let mut ret = vec![];

    let mut state_snapshot_stream = client.get_state_snapshot(version).await?;
    let mut prev_record_bytes: Option<Bytes> = None;
    while let Some(record_bytes) = state_snapshot_stream.read_record_bytes().await? {
        if chunk.len() + size_of::<u32>() + record_bytes.len() > max_chunk_size {
            assert!(chunk.len() <= max_chunk_size);
            let account_state_file = adapter
                .write_new_file(stream::once(async move { chunk }))
                .await?;

            let prb =
                prev_record_bytes.expect("max_chunk_size should be larger than account size.");
            let (prev_key, _): (HashValue, AccountStateBlob) = lcs::from_bytes(&prb)?;
            println!(
                "Reached max_chunk_size. Asking proof for key: {:?}",
                prev_key,
            );
            let proof_file = get_proof_and_write(client, adapter, prev_key, version).await?;
            ret.push((account_state_file, proof_file));
            chunk = vec![];
        }

        chunk.extend(&(record_bytes.len() as u32).to_be_bytes());
        chunk.extend(&record_bytes);
        prev_record_bytes = Some(record_bytes);
    }

    assert!(!chunk.is_empty());
    assert!(chunk.len() <= max_chunk_size);
    let account_state_file = adapter
        .write_new_file(stream::once(async move { chunk }))
        .await?;

    let prb = prev_record_bytes.expect("Should have at least one account.");
    let (prev_key, _): (HashValue, AccountStateBlob) = lcs::from_bytes(&prb)?;
    println!("Asking proof for last key: {:x}", prev_key);
    let proof_file = get_proof_and_write(client, adapter, prev_key, version).await?;
    ret.push((account_state_file, proof_file));

    Ok(ret)
}

async fn get_proof_and_write(
    client: &BackupServiceClient,
    adapter: &impl Adapter,
    key: HashValue,
    version: Version,
) -> Result<FileHandle> {
    let mut proof_bytes = Vec::new();
    client
        .get_account_range_proof(key, version)
        .await?
        .read_to_end(&mut proof_bytes)
        .await?;
    let file = adapter
        .write_new_file(stream::once(async move { proof_bytes }))
        .await?;
    Ok(file)
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website [https://serde.rs/] for additional documentation and
//! usage examples.
//!
//! [https://serde.rs/]: https://serde.rs/
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Bincode], a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a popular human-friendly configuration language that ain't markup
//!   language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [URL], the x-www-form-urlencoded format.
//! - [XML], the flexible machine-friendly W3C standard.
//!   *(deserialization only)*
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Redis], deserialize values from Redis when using [redis-rs].
//!   *(deserialization only)*
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/TyOverby/bincode
//! [CBOR]: https://github.com/pyfisch/cbor
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [Hjson]: https://github.com/laktak/hjson-rust
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [URL]: https://github.com/nox/serde_urlencoded
//! [XML]: https://github.com/RReverser/serde-xml-rs
//! [Envy]: https://github.com/softprops/envy
//! [Redis]: https://github.com/OneSignal/serde-redis
//! [Cargo]: http://doc.crates.io/manifest.html
//! [redis-rs]: https://crates.io/crates/redis

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.18")]

// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]

// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))]
#![cfg_attr(feature = "alloc", feature(alloc))]

#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(
    cast_lossless,
    const_static_lifetime,
    doc_markdown,
    linkedlist,
    type_complexity,
    unreadable_literal,
    zero_prefixed_literal,
))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
// integer and float ser/de requires these sorts of casts
    cast_possible_truncation,
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
// simplifies some macros
    invalid_upcast_comparisons,
// things are often more readable this way
    option_unwrap_used,
    result_unwrap_used,
    shadow_reuse,
    single_match_else,
    stutter,
    use_self,
// not practical
    missing_docs_in_private_items,
// alternative is not stable
    empty_enum,
    use_debug,
))]

// Blacklisted Rust lints.
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(all(feature = "unstable", feature = "std"))]
extern crate core;

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(feature = "std")]
        pub use std::*;
        #[cfg(not(feature = "std"))]
        pub use core::*;
    }

    pub use self::core::{cmp, iter, mem, ops, slice, str};
    pub use self::core::{i8, i16, i32, i64, isize};
    pub use self::core::{u8, u16, u32, u64, usize};
    pub use self::core::{f32, f64};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};

    #[cfg(feature = "std")]
    pub use std::string::String;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};

    #[cfg(feature = "std")]
    pub use std::vec::Vec;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;

    #[cfg(feature = "std")]
    pub use std::boxed::Box;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::Rc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::Rc;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::Arc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::arc::Arc;

    #[cfg(feature = "std")]
    pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CString, CStr, OsString, OsStr};
    #[cfg(feature = "std")]
    pub use std::hash::{Hash, BuildHasher};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::num::Wrapping;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};

    #[cfg(feature = "unstable")]
    pub use core::nonzero::{NonZero, Zeroable};
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

pub mod ser;
pub mod de;

#[doc(inline)]
pub use ser::{Serialize, Serializer};
#[doc(inline)]
pub use de::{Deserialize, Deserializer};

// Generated code uses these to support no_std. Not public API.
#[doc(hidden)]
pub mod export;

// Helpers used by generated code and doc tests. Not public API.
#[doc(hidden)]
pub mod private;

// Re-export #[derive(Serialize, Deserialize)].
//
// This is a workaround for https://github.com/rust-lang/cargo/issues/1286.
// Without this re-export, crates that put Serde derives behind a cfg_attr would
// need to use some silly feature name that depends on both serde and
// serde_derive.
//
//     [features]
//     serde-impls = ["serde", "serde_derive"]
//
//     [dependencies]
//     serde = { version = "1.0", optional = true }
//     serde_derive = { version = "1.0", optional = true }
//
//     # Used like this:
//     # #[cfg(feature = "serde-impls")]
//     # #[macro_use]
//     # extern crate serde_derive;
//     #
//     # #[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The re-exported derives allow crates to use "serde" as the name of their
// Serde feature which is more intuitive.
//
//     [dependencies]
//     serde = { version = "1.0", optional = true, features = ["derive"] }
//
//     # Used like this:
//     # #[cfg(feature = "serde")]
//     # #[macro_use]
//     # extern crate serde;
//     #
//     # #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<commit_msg>Whitelist needless_pass_by_value lint<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website [https://serde.rs/] for additional documentation and
//! usage examples.
//!
//! [https://serde.rs/]: https://serde.rs/
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Bincode], a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a popular human-friendly configuration language that ain't markup
//!   language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [URL], the x-www-form-urlencoded format.
//! - [XML], the flexible machine-friendly W3C standard.
//!   *(deserialization only)*
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Redis], deserialize values from Redis when using [redis-rs].
//!   *(deserialization only)*
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/TyOverby/bincode
//! [CBOR]: https://github.com/pyfisch/cbor
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [Hjson]: https://github.com/laktak/hjson-rust
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [URL]: https://github.com/nox/serde_urlencoded
//! [XML]: https://github.com/RReverser/serde-xml-rs
//! [Envy]: https://github.com/softprops/envy
//! [Redis]: https://github.com/OneSignal/serde-redis
//! [Cargo]: http://doc.crates.io/manifest.html
//! [redis-rs]: https://crates.io/crates/redis

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.18")]

// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]

// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))]
#![cfg_attr(feature = "alloc", feature(alloc))]

#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(
    cast_lossless,
    const_static_lifetime,
    doc_markdown,
    linkedlist,
    needless_pass_by_value,
    type_complexity,
    unreadable_literal,
    zero_prefixed_literal,
))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
// integer and float ser/de requires these sorts of casts
    cast_possible_truncation,
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
// simplifies some macros
    invalid_upcast_comparisons,
// things are often more readable this way
    option_unwrap_used,
    result_unwrap_used,
    shadow_reuse,
    single_match_else,
    stutter,
    use_self,
// not practical
    missing_docs_in_private_items,
// alternative is not stable
    empty_enum,
    use_debug,
))]

// Blacklisted Rust lints.
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(all(feature = "unstable", feature = "std"))]
extern crate core;

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(feature = "std")]
        pub use std::*;
        #[cfg(not(feature = "std"))]
        pub use core::*;
    }

    pub use self::core::{cmp, iter, mem, ops, slice, str};
    pub use self::core::{i8, i16, i32, i64, isize};
    pub use self::core::{u8, u16, u32, u64, usize};
    pub use self::core::{f32, f64};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};

    #[cfg(feature = "std")]
    pub use std::string::String;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};

    #[cfg(feature = "std")]
    pub use std::vec::Vec;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;

    #[cfg(feature = "std")]
    pub use std::boxed::Box;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::Rc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::Rc;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::Arc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::arc::Arc;

    #[cfg(feature = "std")]
    pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CString, CStr, OsString, OsStr};
    #[cfg(feature = "std")]
    pub use std::hash::{Hash, BuildHasher};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::num::Wrapping;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};

    #[cfg(feature = "unstable")]
    pub use core::nonzero::{NonZero, Zeroable};
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

pub mod ser;
pub mod de;

#[doc(inline)]
pub use ser::{Serialize, Serializer};
#[doc(inline)]
pub use de::{Deserialize, Deserializer};

// Generated code uses these to support no_std. Not public API.
#[doc(hidden)]
pub mod export;

// Helpers used by generated code and doc tests. Not public API.
#[doc(hidden)]
pub mod private;

// Re-export #[derive(Serialize, Deserialize)].
//
// This is a workaround for https://github.com/rust-lang/cargo/issues/1286.
// Without this re-export, crates that put Serde derives behind a cfg_attr would
// need to use some silly feature name that depends on both serde and
// serde_derive.
//
//     [features]
//     serde-impls = ["serde", "serde_derive"]
//
//     [dependencies]
//     serde = { version = "1.0", optional = true }
//     serde_derive = { version = "1.0", optional = true }
//
//     # Used like this:
//     # #[cfg(feature = "serde-impls")]
//     # #[macro_use]
//     # extern crate serde_derive;
//     #
//     # #[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The re-exported derives allow crates to use "serde" as the name of their
// Serde feature which is more intuitive.
//
//     [dependencies]
//     serde = { version = "1.0", optional = true, features = ["derive"] }
//
//     # Used like this:
//     # #[cfg(feature = "serde")]
//     # #[macro_use]
//     # extern crate serde;
//     #
//     # #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<|endoftext|>


<commit_before>use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
use getopts::Options;
use sfml::graphics::{RenderTarget, RenderWindow, Sprite, Texture, Transformable};
use sfml::system::Clock;
use sfml::window::{ContextSettings, Event, Key, Style, VideoMode};
use std::fs::File;
use std::io::Read;

fn sfml_key_to_ch8(code: Key) -> Option<u8> {
    Some(match code {
        Key::NUM1 => 1,
        Key::NUM2 => 2,
        Key::NUM3 => 3,
        Key::NUM4 => 0xC,
        Key::Q => 4,
        Key::W => 5,
        Key::E => 6,
        Key::R => 0xD,
        Key::A => 7,
        Key::S => 8,
        Key::D => 9,
        Key::F => 0xE,
        Key::Z => 0xA,
        Key::X => 0,
        Key::C => 0xB,
        Key::V => 0xF,
        _ => return None,
    })
}

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = Vec::new();
    file.read_to_end(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );
    win.set_vertical_sync_enabled(true);

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        while let Some(event) = win.poll_event() {
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::PERIOD {
                        advance = true;
                    } else if let Some(key) = sfml_key_to_ch8(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => {
                    if let Some(key) = sfml_key_to_ch8(code) {
                        ch8.release_key(key);
                    }
                }
                _ => {}
            }
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!(
                "Cycle {}, pc @ {:#x}, ins: {:#x?} raw: {:#x}",
                cycles_made,
                ch8.pc(),
                decode(raw_ins),
                raw_ins
            );
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        render_screen(&mut win, &mut tex, &ch8, scale as f32);
    }
}

fn render_screen(win: &mut RenderWindow, tex: &mut Texture, ch8: &VirtualMachine, scale: f32) {
    let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

    for (i, b) in ch8.display().iter().enumerate() {
        let idx = i * 4;
        if *b == 0u8 {
            for p in pixels[idx..idx + 3].iter_mut() {
                *p = 0;
            }
        }
    }

    unsafe {
        tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
    }
    let mut sprite = Sprite::with_texture(&tex);
    sprite.set_scale((scale, scale));
    win.draw(&sprite);
    win.display();
}

fn main() {
    std::process::exit(run());
}
<commit_msg>Make emulation cycle thingy factored out into function<commit_after>use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
use getopts::Options;
use sfml::graphics::{RenderTarget, RenderWindow, Sprite, Texture, Transformable};
use sfml::system::Clock;
use sfml::window::{ContextSettings, Event, Key, Style, VideoMode};
use std::fs::File;
use std::io::Read;

fn sfml_key_to_ch8(code: Key) -> Option<u8> {
    Some(match code {
        Key::NUM1 => 1,
        Key::NUM2 => 2,
        Key::NUM3 => 3,
        Key::NUM4 => 0xC,
        Key::Q => 4,
        Key::W => 5,
        Key::E => 6,
        Key::R => 0xD,
        Key::A => 7,
        Key::S => 8,
        Key::D => 9,
        Key::F => 0xE,
        Key::Z => 0xA,
        Key::X => 0,
        Key::C => 0xB,
        Key::V => 0xF,
        _ => return None,
    })
}

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = Vec::new();
    file.read_to_end(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );
    win.set_vertical_sync_enabled(true);

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        while let Some(event) = win.poll_event() {
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::PERIOD {
                        advance = true;
                    } else if let Some(key) = sfml_key_to_ch8(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => {
                    if let Some(key) = sfml_key_to_ch8(code) {
                        ch8.release_key(key);
                    }
                }
                _ => {}
            }
        }
        do_emulation_cycle(
            &mut clock,
            &mut ch8,
            paused,
            &mut printed_info,
            &mut cycles_made,
            advance,
        );
        render_screen(&mut win, &mut tex, &ch8, scale as f32);
    }
}

fn do_emulation_cycle(
    clock: &mut Clock,
    ch8: &mut VirtualMachine,
    paused: bool,
    printed_info: &mut bool,
    cycles_made: &mut u64,
    advance: bool,
) {
    if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
        ch8.decrement_timers();
        clock.restart();
    }

    if paused && !*printed_info {
        let raw_ins = ch8.get_ins();
        println!(
            "Cycle {}, pc @ {:#x}, ins: {:#x?} raw: {:#x}",
            cycles_made,
            ch8.pc(),
            decode(raw_ins),
            raw_ins
        );
        *printed_info = true;
    }

    if !paused || advance {
        ch8.do_cycle();
        *cycles_made += 1;
        *printed_info = false;
    }
}

fn render_screen(win: &mut RenderWindow, tex: &mut Texture, ch8: &VirtualMachine, scale: f32) {
    let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

    for (i, b) in ch8.display().iter().enumerate() {
        let idx = i * 4;
        if *b == 0u8 {
            for p in pixels[idx..idx + 3].iter_mut() {
                *p = 0;
            }
        }
    }

    unsafe {
        tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
    }
    let mut sprite = Sprite::with_texture(&tex);
    sprite.set_scale((scale, scale));
    win.draw(&sprite);
    win.display();
}

fn main() {
    std::process::exit(run());
}
<|endoftext|>


<commit_before>use base::math::*;

pub struct Camera {
    pub position: Point3f, // PRP
    // look_at_point: Point3<f32>, // VRP
    pub view_up_vector: Vector3f, // VUV
    pub theta: f32,
    pub phi: f32, // theta_phi: (f32, f32),
}

impl Camera {
    /// Returns the projection matrix
    pub fn proj_matrix(&self) -> Matrix4<f32> {
        perspective(deg(60.0), 16.0 / 9.0, 0.1, 100.0)
    }

    /// Returs view matrix
    pub fn view_matrix(&self) -> Matrix4<f32> {
        Matrix4::look_at(self.position, self.get_look_at_point(), self.view_up_vector)
    }

    /// Calculates the look_at_point by using theta and phi on the unit sphere
    pub fn get_look_at_point(&self) -> Point3f {
        // let lookatvector = self.get_look_at_vector();
        self.position + self.get_look_at_vector()
        // Point3f::new(lookatvector.x + self.position.x,
        //              lookatvector.y + self.position.y,
        //              lookatvector.z + self.position.z)
    }

    pub fn get_look_at_vector(&self) -> Vector3f {
        Vector3f::new(self.theta.sin() * self.phi.cos(),
                      self.theta.sin() * self.phi.sin(),
                      self.theta.cos())
    }

    pub fn move_by(&mut self, pos_diff: Vector3f) {
        self.position += pos_diff;
        // self.position.add_assign(pos_diff);
    }

    /// method to call when forward or backward movement is needed
    /// `factor` is a factor to scale the movement speed
    /// `factor` has to be positive for foward movement
    /// `factor` has to be negative for backward movement
    pub fn move_forward_backward(&mut self, factor: f32) {
        // maybe implement the function so the factor is a parameter (to regulate speed
        // with shift)
        let mut lookatvector = self.get_look_at_vector();
        lookatvector.z = 0.0;
        lookatvector.normalize();
        lookatvector *= factor;
        self.move_by(lookatvector); //does the "self" have to be here?
    }

    /// method to call when left or right movement is needed
    /// `factor` is a factor to scale the movement speed
    /// `factor` has to be positive for left movement
    /// `factor` has to be negative for right movement
    pub fn move_left_right(&mut self, factor: f32) {
        let mut lookatvector = self.get_look_at_vector();
        lookatvector.z = 0.0;
        lookatvector.normalize();
        // Get the orthogonal 2d-vector, which is 90 degrees to the left
        let mut move_dir = Vector3f::new(-lookatvector.y, lookatvector.x, 0.0);
        move_dir *= factor;
        self.move_by(move_dir);

    }

    /// method to call when upward or downward movement is needed
    /// `factor` is a factor to scale the movement speed
    /// `factor` has to be positive for upward movement
    /// `factor` has to be negative for downward movement
    pub fn move_up_down(&mut self, factor: f32) {
        self.move_by(Vector3f::new(0.0, 0.0, factor));
    }

    // Used in move_forward_backward
    // pub fn move_backward(&self) {
    //     let factor = -1.0;
    //     let lookatvector = get_look_at_vector();
    //     lookatvector.z = 0;
    //     lookatvector.normalize();
    //     lookatvector.mul_assign(factor);
    //     self.move_by(lookatvector); //does the "self" have to be here?
    // }
    // später mehtoden wie move_forward

    pub fn change_dir(&mut self, theta_diff: f32, phi_diff: f32) {
        self.theta += theta_diff;
        self.phi += phi_diff;
        // new matrix will be calculated
    }

    // pub fn view_matrix(&self) -> Matrix4<f32> {
    //     let N: Vector3 = (self.position).sub(self.look_at_point);
    //     let V: Vector3 = (N.cross(self.view_up_vector)).cross(N);
    //     let U: Vector3 = V.cross(N);
    //     Matrix4::new(U, V, N)
    // }
}
<commit_msg>uncomment non-essential methods for a lighter code review workload<commit_after>use base::math::*;

pub struct Camera {
    pub position: Point3f, // PRP
    // look_at_point: Point3<f32>, // VRP
    pub view_up_vector: Vector3f, // VUV
    pub theta: f32,
    pub phi: f32, // theta_phi: (f32, f32),
}

impl Camera {
    /// Returns the projection matrix
    pub fn proj_matrix(&self) -> Matrix4<f32> {
        perspective(deg(60.0), 16.0 / 9.0, 0.1, 100.0)
    }

    /// Returs view matrix
    pub fn view_matrix(&self) -> Matrix4<f32> {
        Matrix4::look_at(self.position, self.get_look_at_point(), self.view_up_vector)
    }

    /// Calculates the look_at_point by using theta and phi on the unit sphere
    pub fn get_look_at_point(&self) -> Point3f {
        // let lookatvector = self.get_look_at_vector();
        self.position + self.get_look_at_vector()
        // Point3f::new(lookatvector.x + self.position.x,
        //              lookatvector.y + self.position.y,
        //              lookatvector.z + self.position.z)
    }

    pub fn get_look_at_vector(&self) -> Vector3f {
        Vector3f::new(self.theta.sin() * self.phi.cos(),
                      self.theta.sin() * self.phi.sin(),
                      self.theta.cos())
    }

    pub fn move_by(&mut self, pos_diff: Vector3f) {
        self.position += pos_diff;
        // self.position.add_assign(pos_diff);
    }

    /// method to call when forward or backward movement is needed
    /// `factor` is a factor to scale the movement speed
    /// `factor` has to be positive for foward movement
    /// `factor` has to be negative for backward movement
    pub fn move_forward_backward(&mut self, factor: f32) {
        // maybe implement the function so the factor is a parameter (to regulate speed
        // with shift)
        let mut lookatvector = self.get_look_at_vector();
        lookatvector.z = 0.0;
        lookatvector.normalize();
        lookatvector *= factor;
        self.move_by(lookatvector); //does the "self" have to be here?
    }

    /// method to call when left or right movement is needed
    /// `factor` is a factor to scale the movement speed
    /// `factor` has to be positive for left movement
    /// `factor` has to be negative for right movement
    // pub fn move_left_right(&mut self, factor: f32) {
    //     let mut lookatvector = self.get_look_at_vector();
    //     lookatvector.z = 0.0;
    //     lookatvector.normalize();
    //     // Get the orthogonal 2d-vector, which is 90 degrees to the left
    // let mut move_dir = Vector3f::new(-lookatvector.y, lookatvector.x,
    // 0.0);
    //     move_dir *= factor;
    //     self.move_by(move_dir);
    //
    // }
    /// method to call when upward or downward movement is needed
    /// `factor` is a factor to scale the movement speed
    /// `factor` has to be positive for upward movement
    /// `factor` has to be negative for downward movement
    // pub fn move_up_down(&mut self, factor: f32) {
    //     self.move_by(Vector3f::new(0.0, 0.0, factor));
    // }

    pub fn change_dir(&mut self, theta_diff: f32, phi_diff: f32) {
        self.theta += theta_diff;
        self.phi += phi_diff;
        // new matrix will be calculated
    }
}
<|endoftext|>