<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use crate::context::*;
use crate::partition::*;

use std::cmp;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use std::slice;

/// Tiled view of FrameBlocks
#[derive(Debug)]
pub struct TileBlocks<'a> {
  data: *const Block,
  x: usize,
  y: usize,
  cols: usize,
  rows: usize,
  stride: usize, // number of cols in the underlying FrameBlocks
  phantom: PhantomData<&'a Block>,
}

/// Mutable tiled view of FrameBlocks
#[derive(Debug)]
pub struct TileBlocksMut<'a> {
  data: *mut Block,
  // private to guarantee borrowing rules
  x: usize,
  y: usize,
  cols: usize,
  rows: usize,
  stride: usize, // number of cols in the underlying FrameBlocks
  phantom: PhantomData<&'a mut Block>,
}

// common impl for TileBlocks and TileBlocksMut
macro_rules! tile_blocks_common {
  // $name: TileBlocks or TileBlocksMut
  // $opt_mut: nothing or mut
  ($name:ident $(,$opt_mut:tt)?) => {
    impl<'a> $name<'a> {

      #[inline(always)]
      pub fn new(
        frame_blocks: &'a $($opt_mut)? FrameBlocks,
        x: usize,
        y: usize,
        cols: usize,
        rows: usize,
      ) -> Self {
        Self {
          data: & $($opt_mut)? frame_blocks[y][x],
          x,
          y,
          cols,
          rows,
          stride: frame_blocks.cols,
          phantom: PhantomData,
        }
      }

      #[inline(always)]
      pub fn x(&self) -> usize {
        self.x
      }

      #[inline(always)]
      pub fn y(&self) -> usize {
        self.y
      }

      #[inline(always)]
      pub fn cols(&self) -> usize {
        self.cols
      }

      #[inline(always)]
      pub fn rows(&self) -> usize {
        self.rows
      }

      #[inline(always)]
      pub fn above_of(&self, bo: BlockOffset) -> &Block {
        &self[bo.y - 1][bo.x]
      }

      #[inline(always)]
      pub fn left_of(&self, bo: BlockOffset) -> &Block {
        &self[bo.y][bo.x - 1]
      }

      #[inline(always)]
      pub fn above_left_of(&self, bo: BlockOffset) -> &Block {
        &self[bo.y - 1][bo.x - 1]
      }

      pub fn get_cdef(&self, sbo: SuperBlockOffset) -> u8 {
        let bo = sbo.block_offset(0, 0);
        self[bo.y][bo.x].cdef_index
      }
    }

    unsafe impl Send for $name<'_> {}
    unsafe impl Sync for $name<'_> {}

    impl Index<usize> for $name<'_> {
      type Output = [Block];
      #[inline(always)]
      fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.rows);
        unsafe {
          let ptr = self.data.add(index * self.stride);
          slice::from_raw_parts(ptr, self.cols)
        }
      }
    }

    // for convenience, also index by BlockOffset
    impl Index<BlockOffset> for $name<'_> {
      type Output = Block;
      #[inline(always)]
      fn index(&self, bo: BlockOffset) -> &Self::Output {
        &self[bo.y][bo.x]
      }
    }
  }
}

tile_blocks_common!(TileBlocks);
tile_blocks_common!(TileBlocksMut, mut);

impl TileBlocksMut<'_> {
  #[inline(always)]
  pub fn as_const(&self) -> TileBlocks<'_> {
    TileBlocks {
      data: self.data,
      x: self.x,
      y: self.y,
      cols: self.cols,
      rows: self.rows,
      stride: self.stride,
      phantom: PhantomData,
    }
  }

  pub fn for_each<F>(&mut self, bo: BlockOffset, bsize: BlockSize, f: F)
  where
    F: Fn(&mut Block) -> (),
  {
    let bw = bsize.width_mi();
    let bh = bsize.height_mi();
    for y in 0..bh {
      for x in 0..bw {
        f(&mut self[bo.y + y as usize][bo.x + x as usize]);
      }
    }
  }

  pub fn set_mode(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    mode: PredictionMode,
  ) {
    self.for_each(bo, bsize, |block| block.mode = mode);
  }

  pub fn set_block_size(&mut self, bo: BlockOffset, bsize: BlockSize) {
    let n4_w = bsize.width_mi();
    let n4_h = bsize.height_mi();
    self.for_each(bo, bsize, |block| {
      block.bsize = bsize;
      block.n4_w = n4_w;
      block.n4_h = n4_h
    });
  }

  pub fn set_tx_size(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    tx_size: TxSize,
  ) {
    self.for_each(bo, bsize, |block| block.txsize = tx_size);
  }

  pub fn set_skip(&mut self, bo: BlockOffset, bsize: BlockSize, skip: bool) {
    self.for_each(bo, bsize, |block| block.skip = skip);
  }

  pub fn set_segmentation_idx(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    idx: u8,
  ) {
    self.for_each(bo, bsize, |block| block.segmentation_idx = idx);
  }

  pub fn set_ref_frames(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    r: [RefType; 2],
  ) {
    self.for_each(bo, bsize, |block| block.ref_frames = r);
  }

  pub fn set_motion_vectors(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    mvs: [MotionVector; 2],
  ) {
    self.for_each(bo, bsize, |block| block.mv = mvs);
  }

  pub fn set_cdef(&mut self, sbo: SuperBlockOffset, cdef_index: u8) {
    let bo = sbo.block_offset(0, 0);
    // Checkme: Is 16 still the right block unit for 128x128 superblocks?
    let bw = cmp::min(bo.x + MAX_MIB_SIZE, self.cols);
    let bh = cmp::min(bo.y + MAX_MIB_SIZE, self.rows);
    for y in bo.y..bh {
      for x in bo.x..bw {
        self[y as usize][x as usize].cdef_index = cdef_index;
      }
    }
  }
}

impl IndexMut<usize> for TileBlocksMut<'_> {
  #[inline(always)]
  fn index_mut(&mut self, index: usize) -> &mut Self::Output {
    assert!(index < self.rows);
    unsafe {
      let ptr = self.data.add(index * self.stride);
      slice::from_raw_parts_mut(ptr, self.cols)
    }
  }
}

impl IndexMut<BlockOffset> for TileBlocksMut<'_> {
  #[inline(always)]
  fn index_mut(&mut self, bo: BlockOffset) -> &mut Self::Output {
    &mut self[bo.y][bo.x]
  }
}
<commit_msg>Expose frame blocks size in TileBlocks<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use crate::context::*;
use crate::partition::*;

use std::cmp;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use std::slice;

/// Tiled view of FrameBlocks
#[derive(Debug)]
pub struct TileBlocks<'a> {
  data: *const Block,
  x: usize,
  y: usize,
  cols: usize,
  rows: usize,
  frame_cols: usize,
  frame_rows: usize,
  phantom: PhantomData<&'a Block>,
}

/// Mutable tiled view of FrameBlocks
#[derive(Debug)]
pub struct TileBlocksMut<'a> {
  data: *mut Block,
  // private to guarantee borrowing rules
  x: usize,
  y: usize,
  cols: usize,
  rows: usize,
  pub frame_cols: usize,
  pub frame_rows: usize,
  phantom: PhantomData<&'a mut Block>,
}

// common impl for TileBlocks and TileBlocksMut
macro_rules! tile_blocks_common {
  // $name: TileBlocks or TileBlocksMut
  // $opt_mut: nothing or mut
  ($name:ident $(,$opt_mut:tt)?) => {
    impl<'a> $name<'a> {

      #[inline(always)]
      pub fn new(
        frame_blocks: &'a $($opt_mut)? FrameBlocks,
        x: usize,
        y: usize,
        cols: usize,
        rows: usize,
      ) -> Self {
        Self {
          data: & $($opt_mut)? frame_blocks[y][x],
          x,
          y,
          cols,
          rows,
          frame_cols: frame_blocks.cols,
          frame_rows: frame_blocks.rows,
          phantom: PhantomData,
        }
      }

      #[inline(always)]
      pub fn x(&self) -> usize {
        self.x
      }

      #[inline(always)]
      pub fn y(&self) -> usize {
        self.y
      }

      #[inline(always)]
      pub fn cols(&self) -> usize {
        self.cols
      }

      #[inline(always)]
      pub fn rows(&self) -> usize {
        self.rows
      }

      #[inline(always)]
      pub fn above_of(&self, bo: BlockOffset) -> &Block {
        &self[bo.y - 1][bo.x]
      }

      #[inline(always)]
      pub fn left_of(&self, bo: BlockOffset) -> &Block {
        &self[bo.y][bo.x - 1]
      }

      #[inline(always)]
      pub fn above_left_of(&self, bo: BlockOffset) -> &Block {
        &self[bo.y - 1][bo.x - 1]
      }

      pub fn get_cdef(&self, sbo: SuperBlockOffset) -> u8 {
        let bo = sbo.block_offset(0, 0);
        self[bo.y][bo.x].cdef_index
      }
    }

    unsafe impl Send for $name<'_> {}
    unsafe impl Sync for $name<'_> {}

    impl Index<usize> for $name<'_> {
      type Output = [Block];
      #[inline(always)]
      fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.rows);
        unsafe {
          let ptr = self.data.add(index * self.frame_cols);
          slice::from_raw_parts(ptr, self.cols)
        }
      }
    }

    // for convenience, also index by BlockOffset
    impl Index<BlockOffset> for $name<'_> {
      type Output = Block;
      #[inline(always)]
      fn index(&self, bo: BlockOffset) -> &Self::Output {
        &self[bo.y][bo.x]
      }
    }
  }
}

tile_blocks_common!(TileBlocks);
tile_blocks_common!(TileBlocksMut, mut);

impl TileBlocksMut<'_> {
  #[inline(always)]
  pub fn as_const(&self) -> TileBlocks<'_> {
    TileBlocks {
      data: self.data,
      x: self.x,
      y: self.y,
      cols: self.cols,
      rows: self.rows,
      frame_cols: self.frame_cols,
      frame_rows: self.frame_rows,
      phantom: PhantomData,
    }
  }

  pub fn for_each<F>(&mut self, bo: BlockOffset, bsize: BlockSize, f: F)
  where
    F: Fn(&mut Block) -> (),
  {
    let bw = bsize.width_mi();
    let bh = bsize.height_mi();
    for y in 0..bh {
      for x in 0..bw {
        f(&mut self[bo.y + y as usize][bo.x + x as usize]);
      }
    }
  }

  pub fn set_mode(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    mode: PredictionMode,
  ) {
    self.for_each(bo, bsize, |block| block.mode = mode);
  }

  pub fn set_block_size(&mut self, bo: BlockOffset, bsize: BlockSize) {
    let n4_w = bsize.width_mi();
    let n4_h = bsize.height_mi();
    self.for_each(bo, bsize, |block| {
      block.bsize = bsize;
      block.n4_w = n4_w;
      block.n4_h = n4_h
    });
  }

  pub fn set_tx_size(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    tx_size: TxSize,
  ) {
    self.for_each(bo, bsize, |block| block.txsize = tx_size);
  }

  pub fn set_skip(&mut self, bo: BlockOffset, bsize: BlockSize, skip: bool) {
    self.for_each(bo, bsize, |block| block.skip = skip);
  }

  pub fn set_segmentation_idx(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    idx: u8,
  ) {
    self.for_each(bo, bsize, |block| block.segmentation_idx = idx);
  }

  pub fn set_ref_frames(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    r: [RefType; 2],
  ) {
    self.for_each(bo, bsize, |block| block.ref_frames = r);
  }

  pub fn set_motion_vectors(
    &mut self,
    bo: BlockOffset,
    bsize: BlockSize,
    mvs: [MotionVector; 2],
  ) {
    self.for_each(bo, bsize, |block| block.mv = mvs);
  }

  pub fn set_cdef(&mut self, sbo: SuperBlockOffset, cdef_index: u8) {
    let bo = sbo.block_offset(0, 0);
    // Checkme: Is 16 still the right block unit for 128x128 superblocks?
    let bw = cmp::min(bo.x + MAX_MIB_SIZE, self.cols);
    let bh = cmp::min(bo.y + MAX_MIB_SIZE, self.rows);
    for y in bo.y..bh {
      for x in bo.x..bw {
        self[y as usize][x as usize].cdef_index = cdef_index;
      }
    }
  }
}

impl IndexMut<usize> for TileBlocksMut<'_> {
  #[inline(always)]
  fn index_mut(&mut self, index: usize) -> &mut Self::Output {
    assert!(index < self.rows);
    unsafe {
      let ptr = self.data.add(index * self.frame_cols);
      slice::from_raw_parts_mut(ptr, self.cols)
    }
  }
}

impl IndexMut<BlockOffset> for TileBlocksMut<'_> {
  #[inline(always)]
  fn index_mut(&mut self, bo: BlockOffset) -> &mut Self::Output {
    &mut self[bo.y][bo.x]
  }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    common::{
        types::{CliError, CliTypedResult},
        utils::write_to_file,
    },
    genesis::config::Layout,
    CliCommand,
};
use aptos_config::config::Token;
use aptos_github_client::Client as GithubClient;
use async_trait::async_trait;
use clap::Parser;
use serde::{de::DeserializeOwned, Serialize};
use std::{io::Read, path::PathBuf, str::FromStr};

pub const LAYOUT_NAME: &str = "layout";

/// Setup a shared Github repository for Genesis
///
#[derive(Parser)]
pub struct SetupGit {
    #[clap(flatten)]
    git_options: GitOptions,
    /// Path to `Layout` which defines where all the files are
    #[clap(long, parse(from_os_str))]
    layout_file: PathBuf,
}

#[async_trait]
impl CliCommand<()> for SetupGit {
    fn command_name(&self) -> &'static str {
        "SetupGit"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let layout = Layout::from_disk(&self.layout_file)?;

        // Upload layout file to ensure we can read later
        let client = self.git_options.get_client()?;
        client.put(LAYOUT_NAME, &layout)?;

        // Make a place for the modules to be uploaded
        client.create_dir("framework")?;

        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct GithubRepo {
    owner: String,
    repository: String,
}

impl FromStr for GithubRepo {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split('/').collect();
        if parts.len() != 2 {
            Err(CliError::CommandArgumentError("Invalid repository must be of the form 'owner/repository` e.g. 'aptos-labs/aptos-core'".to_string()))
        } else {
            Ok(GithubRepo {
                owner: parts.get(0).unwrap().to_string(),
                repository: parts.get(1).unwrap().to_string(),
            })
        }
    }
}

#[derive(Clone, Parser)]
pub struct GitOptions {
    /// Github repository e.g. 'aptos-labs/aptos-core'
    #[clap(long)]
    github_repository: Option<GithubRepo>,
    /// Github repository branch e.g. main
    #[clap(long, default_value = "main")]
    github_branch: String,
    /// Path to Github API token.  Token must have repo:* permissions
    #[clap(long, parse(from_os_str))]
    github_token_file: Option<PathBuf>,
    /// Path to local git repository
    #[clap(long, parse(from_os_str))]
    local_repository_dir: Option<PathBuf>,
}

impl GitOptions {
    pub fn get_client(self) -> CliTypedResult<Client> {
        if self.github_repository.is_none()
            && self.github_token_file.is_none()
            && self.local_repository_dir.is_some()
        {
            Ok(Client::local(self.local_repository_dir.unwrap()))
        } else if self.github_repository.is_some()
            && self.github_token_file.is_some()
            && self.local_repository_dir.is_none()
        {
            Client::github(
                self.github_repository.unwrap(),
                self.github_branch,
                self.github_token_file.unwrap(),
            )
        } else {
            Err(CliError::CommandArgumentError("Must provide either only --local-repository-path or both --github-repository and --github-token-path".to_string()))
        }
    }
}

/// A client for abstracting away local vs Github storage
///
/// Note: Writes do not commit locally
pub enum Client {
    Local(PathBuf),
    Github(GithubClient),
}

impl Client {
    pub fn local(path: PathBuf) -> Client {
        Client::Local(path)
    }

    pub fn github(
        repository: GithubRepo,
        branch: String,
        token_path: PathBuf,
    ) -> CliTypedResult<Client> {
        let token = Token::FromDisk(token_path).read_token()?;
        Ok(Client::Github(GithubClient::new(
            repository.owner,
            repository.repository,
            branch,
            token,
        )))
    }

    /// Retrieves an object as a YAML encoded file from the appropriate storage
    pub fn get<T: DeserializeOwned>(&self, name: &str) -> CliTypedResult<T> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(format!("{}.yml", name));
                let mut file = std::fs::File::open(path.as_path())
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;

                let mut contents = String::new();
                file.read_to_string(&mut contents)
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;
                from_yaml(&contents)
            }
            Client::Github(client) => {
                from_base64_encoded_yaml(&client.get_file(&format!("{}.yml", name))?)
            }
        }
    }

    /// Puts an object as a YAML encoded file to the appropriate storage
    pub fn put<T: Serialize + ?Sized>(&self, name: &str, input: &T) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(format!("{}.yml", name));
                write_to_file(
                    path.as_path(),
                    &path.display().to_string(),
                    to_yaml(input)?.as_bytes(),
                )?;
            }
            Client::Github(client) => {
                client.put(&format!("{}.yml", name), &to_base64_encoded_yaml(input)?)?;
            }
        }

        Ok(())
    }

    pub fn create_dir(&self, name: &str) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(name);
                if path.exists() && path.is_dir() {
                    // Do nothing
                } else {
                    std::fs::create_dir(path.as_path())
                        .map_err(|e| CliError::IO(path.display().to_string(), e))?
                };
            }
            Client::Github(_) => {
                // There's no such thing as an empty directory in Git, so do nothing
            }
        }

        Ok(())
    }

    /// Retrieve bytecode Move modules from a module folder
    pub fn get_modules(&self, name: &str) -> CliTypedResult<Vec<Vec<u8>>> {
        let mut modules = Vec::new();

        match self {
            Client::Local(local_repository_path) => {
                let module_folder = local_repository_path.join(name);
                if !module_folder.is_dir() {
                    return Err(CliError::UnexpectedError(format!(
                        "{} is not a directory!",
                        module_folder.display()
                    )));
                }

                let files = std::fs::read_dir(module_folder.as_path())
                    .map_err(|e| CliError::IO(module_folder.display().to_string(), e))?;

                for maybe_file in files {
                    let file = maybe_file
                        .map_err(|e| CliError::UnexpectedError(e.to_string()))?
                        .path();
                    let extension = file.extension();

                    // Only collect move files
                    if file.is_file() && extension.is_some() && extension.unwrap() == "mv" {
                        modules.push(
                            std::fs::read(file.as_path())
                                .map_err(|e| CliError::IO(file.display().to_string(), e))?,
                        );
                    }
                }
            }
            Client::Github(client) => {
                let files = client.get_directory(name)?;

                for file in files {
                    // Only collect .mv files
                    if file.ends_with(".mv") {
                        modules.push(base64::decode(client.get_file(&file)?)?)
                    }
                }
            }
        }
        Ok(modules)
    }
}

pub fn to_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(serde_yaml::to_string(input)?)
}

pub fn from_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    Ok(serde_yaml::from_str(input)?)
}

pub fn to_base64_encoded_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(base64::encode(to_yaml(input)?))
}

pub fn from_base64_encoded_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    from_yaml(&String::from_utf8(base64::decode(input)?)?)
}
<commit_msg>[aptos-cli] Fix broken error message on git options<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    common::{
        types::{CliError, CliTypedResult},
        utils::write_to_file,
    },
    genesis::config::Layout,
    CliCommand,
};
use aptos_config::config::Token;
use aptos_github_client::Client as GithubClient;
use async_trait::async_trait;
use clap::Parser;
use serde::{de::DeserializeOwned, Serialize};
use std::{io::Read, path::PathBuf, str::FromStr};

pub const LAYOUT_NAME: &str = "layout";

/// Setup a shared Github repository for Genesis
///
#[derive(Parser)]
pub struct SetupGit {
    #[clap(flatten)]
    git_options: GitOptions,
    /// Path to `Layout` which defines where all the files are
    #[clap(long, parse(from_os_str))]
    layout_file: PathBuf,
}

#[async_trait]
impl CliCommand<()> for SetupGit {
    fn command_name(&self) -> &'static str {
        "SetupGit"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let layout = Layout::from_disk(&self.layout_file)?;

        // Upload layout file to ensure we can read later
        let client = self.git_options.get_client()?;
        client.put(LAYOUT_NAME, &layout)?;

        // Make a place for the modules to be uploaded
        client.create_dir("framework")?;

        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct GithubRepo {
    owner: String,
    repository: String,
}

impl FromStr for GithubRepo {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split('/').collect();
        if parts.len() != 2 {
            Err(CliError::CommandArgumentError("Invalid repository must be of the form 'owner/repository` e.g. 'aptos-labs/aptos-core'".to_string()))
        } else {
            Ok(GithubRepo {
                owner: parts.get(0).unwrap().to_string(),
                repository: parts.get(1).unwrap().to_string(),
            })
        }
    }
}

#[derive(Clone, Parser)]
pub struct GitOptions {
    /// Github repository e.g. 'aptos-labs/aptos-core'
    #[clap(long)]
    github_repository: Option<GithubRepo>,
    /// Github repository branch e.g. main
    #[clap(long, default_value = "main")]
    github_branch: String,
    /// Path to Github API token.  Token must have repo:* permissions
    #[clap(long, parse(from_os_str))]
    github_token_file: Option<PathBuf>,
    /// Path to local git repository
    #[clap(long, parse(from_os_str))]
    local_repository_dir: Option<PathBuf>,
}

impl GitOptions {
    pub fn get_client(self) -> CliTypedResult<Client> {
        if self.github_repository.is_none()
            && self.github_token_file.is_none()
            && self.local_repository_dir.is_some()
        {
            Ok(Client::local(self.local_repository_dir.unwrap()))
        } else if self.github_repository.is_some()
            && self.github_token_file.is_some()
            && self.local_repository_dir.is_none()
        {
            Client::github(
                self.github_repository.unwrap(),
                self.github_branch,
                self.github_token_file.unwrap(),
            )
        } else {
            Err(CliError::CommandArgumentError("Must provide either only --local-repository-dir or both --github-repository and --github-token-path".to_string()))
        }
    }
}

/// A client for abstracting away local vs Github storage
///
/// Note: Writes do not commit locally
pub enum Client {
    Local(PathBuf),
    Github(GithubClient),
}

impl Client {
    pub fn local(path: PathBuf) -> Client {
        Client::Local(path)
    }

    pub fn github(
        repository: GithubRepo,
        branch: String,
        token_path: PathBuf,
    ) -> CliTypedResult<Client> {
        let token = Token::FromDisk(token_path).read_token()?;
        Ok(Client::Github(GithubClient::new(
            repository.owner,
            repository.repository,
            branch,
            token,
        )))
    }

    /// Retrieves an object as a YAML encoded file from the appropriate storage
    pub fn get<T: DeserializeOwned>(&self, name: &str) -> CliTypedResult<T> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(format!("{}.yml", name));
                let mut file = std::fs::File::open(path.as_path())
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;

                let mut contents = String::new();
                file.read_to_string(&mut contents)
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;
                from_yaml(&contents)
            }
            Client::Github(client) => {
                from_base64_encoded_yaml(&client.get_file(&format!("{}.yml", name))?)
            }
        }
    }

    /// Puts an object as a YAML encoded file to the appropriate storage
    pub fn put<T: Serialize + ?Sized>(&self, name: &str, input: &T) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(format!("{}.yml", name));
                write_to_file(
                    path.as_path(),
                    &path.display().to_string(),
                    to_yaml(input)?.as_bytes(),
                )?;
            }
            Client::Github(client) => {
                client.put(&format!("{}.yml", name), &to_base64_encoded_yaml(input)?)?;
            }
        }

        Ok(())
    }

    pub fn create_dir(&self, name: &str) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(name);
                if path.exists() && path.is_dir() {
                    // Do nothing
                } else {
                    std::fs::create_dir(path.as_path())
                        .map_err(|e| CliError::IO(path.display().to_string(), e))?
                };
            }
            Client::Github(_) => {
                // There's no such thing as an empty directory in Git, so do nothing
            }
        }

        Ok(())
    }

    /// Retrieve bytecode Move modules from a module folder
    pub fn get_modules(&self, name: &str) -> CliTypedResult<Vec<Vec<u8>>> {
        let mut modules = Vec::new();

        match self {
            Client::Local(local_repository_path) => {
                let module_folder = local_repository_path.join(name);
                if !module_folder.is_dir() {
                    return Err(CliError::UnexpectedError(format!(
                        "{} is not a directory!",
                        module_folder.display()
                    )));
                }

                let files = std::fs::read_dir(module_folder.as_path())
                    .map_err(|e| CliError::IO(module_folder.display().to_string(), e))?;

                for maybe_file in files {
                    let file = maybe_file
                        .map_err(|e| CliError::UnexpectedError(e.to_string()))?
                        .path();
                    let extension = file.extension();

                    // Only collect move files
                    if file.is_file() && extension.is_some() && extension.unwrap() == "mv" {
                        modules.push(
                            std::fs::read(file.as_path())
                                .map_err(|e| CliError::IO(file.display().to_string(), e))?,
                        );
                    }
                }
            }
            Client::Github(client) => {
                let files = client.get_directory(name)?;

                for file in files {
                    // Only collect .mv files
                    if file.ends_with(".mv") {
                        modules.push(base64::decode(client.get_file(&file)?)?)
                    }
                }
            }
        }
        Ok(modules)
    }
}

pub fn to_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(serde_yaml::to_string(input)?)
}

pub fn from_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    Ok(serde_yaml::from_str(input)?)
}

pub fn to_base64_encoded_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(base64::encode(to_yaml(input)?))
}

pub fn from_base64_encoded_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    from_yaml(&String::from_utf8(base64::decode(input)?)?)
}
<|endoftext|>


<commit_before>// Copyright 2017 Amos Onn.
//
// 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.
//

use std::result;
use std::ffi::OsStr;
use std::path::Path;
use libc;

pub type Result<T> = result::Result<T, libc::c_int>;

use super::fusefl::*;
use fuse_mt::*;

pub trait ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>;
}

pub trait WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>;

    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

pub enum NoFile {}

#[allow(unused_variables)]
impl ReadFileLike for NoFile {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }
}

#[allow(unused_variables)]
impl WriteFileLike for NoFile {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }

    fn flush(&self) -> Result<()> {
        Err(libc::ENOSYS)
    }
}

pub struct ReadWriteAdaptor<R, W> {
    reader: R,
    writer: W,
}

impl<R, W> ReadFileLike for ReadWriteAdaptor<R, W> where R: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        self.reader.read_at(buf, offset)
    }
}

impl<R, W> WriteFileLike for ReadWriteAdaptor<R, W> where W: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        self.writer.write_at(buf, offset)
    }

    fn flush(&self) -> Result<()> {
        self.writer.flush()
    }
}

pub enum ModalFileLike<R, W, RW> {
    ReadOnly(R),
    WriteOnly(W),
    ReadWrite(RW),
}

use self::ModalFileLike::*;

impl<R, W, RW> ReadFileLike for ModalFileLike<R, W, RW> where
    R: ReadFileLike, RW: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(ref r) => r.read_at(buf, offset),
            WriteOnly(_) => Err(libc::EBADF),
            ReadWrite(ref rw) => rw.read_at(buf, offset),
        }
    }
}

impl<R, W, RW> WriteFileLike for ModalFileLike<R, W, RW> where
    W: WriteFileLike, RW: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.write_at(buf, offset),
            ReadWrite(ref rw) => rw.write_at(buf, offset),
        }
    }

    fn flush(&self) -> Result<()> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.flush(),
            ReadWrite(ref rw) => rw.flush(),
        }
    }
}

pub trait FilesystemFLRwOpen {
    type ReadLike: ReadFileLike; // = NoFile;
    type WriteLike: WriteFileLike; // = NoFile;
    type ReadWriteLike: ReadFileLike+WriteFileLike; // = ReadWriteAdaptor<Self::ReadLike, Self::WriteLike>;

    fn open_read(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn open_write(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn open_readwrite(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_write(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_readwrite(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
pub trait FilesystemFLOpen {
    type FileLike: ReadFileLike+WriteFileLike;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    fn read(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _size: u32) -> ResultData {
        let _size = _size as usize;
        let mut vec = Vec::<u8>::with_capacity(_size);
        unsafe { vec.set_len(_size) };
        let num_read = _fl.read_at(vec.as_mut_slice(), _offset)?;
        assert!(num_read <= _size);
        unsafe { vec.set_len(num_read) };
        Ok(vec)
    }

    fn write(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _data: Vec<u8>, _flags: u32) -> ResultWrite {
        assert!(_data.len() <= u32::max_value() as usize);
        _fl.write_at(_data.as_slice(), _offset).map(|x| x as u32)
    }

    fn fsync(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _datasync: bool) -> ResultEmpty {
        Err(libc::ENOSYS)
    }
}
<commit_msg>Added fsync support for FilesystemFLOpen.<commit_after>// Copyright 2017 Amos Onn.
//
// 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.
//

use std::result;
use std::ffi::OsStr;
use std::path::Path;
use libc;

pub type Result<T> = result::Result<T, libc::c_int>;

use super::fusefl::*;
use fuse_mt::*;

pub trait ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>;
}

pub trait WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>;

    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

pub enum NoFile {}

#[allow(unused_variables)]
impl ReadFileLike for NoFile {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }
}

#[allow(unused_variables)]
impl WriteFileLike for NoFile {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }

    fn flush(&self) -> Result<()> {
        Err(libc::ENOSYS)
    }
}

pub struct ReadWriteAdaptor<R, W> {
    reader: R,
    writer: W,
}

impl<R, W> ReadFileLike for ReadWriteAdaptor<R, W> where R: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        self.reader.read_at(buf, offset)
    }
}

impl<R, W> WriteFileLike for ReadWriteAdaptor<R, W> where W: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        self.writer.write_at(buf, offset)
    }

    fn flush(&self) -> Result<()> {
        self.writer.flush()
    }
}

pub enum ModalFileLike<R, W, RW> {
    ReadOnly(R),
    WriteOnly(W),
    ReadWrite(RW),
}

use self::ModalFileLike::*;

impl<R, W, RW> ReadFileLike for ModalFileLike<R, W, RW> where
    R: ReadFileLike, RW: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(ref r) => r.read_at(buf, offset),
            WriteOnly(_) => Err(libc::EBADF),
            ReadWrite(ref rw) => rw.read_at(buf, offset),
        }
    }
}

impl<R, W, RW> WriteFileLike for ModalFileLike<R, W, RW> where
    W: WriteFileLike, RW: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.write_at(buf, offset),
            ReadWrite(ref rw) => rw.write_at(buf, offset),
        }
    }

    fn flush(&self) -> Result<()> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.flush(),
            ReadWrite(ref rw) => rw.flush(),
        }
    }
}

pub trait FilesystemFLRwOpen {
    type ReadLike: ReadFileLike; // = NoFile;
    type WriteLike: WriteFileLike; // = NoFile;
    type ReadWriteLike: ReadFileLike+WriteFileLike; // = ReadWriteAdaptor<Self::ReadLike, Self::WriteLike>;

    fn open_read(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn open_write(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn open_readwrite(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_write(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_readwrite(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
pub trait FilesystemFLOpen {
    type FileLike: ReadFileLike+WriteFileLike;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    fn read(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _size: u32) -> ResultData {
        let _size = _size as usize;
        let mut vec = Vec::<u8>::with_capacity(_size);
        unsafe { vec.set_len(_size) };
        let num_read = _fl.read_at(vec.as_mut_slice(), _offset)?;
        assert!(num_read <= _size);
        unsafe { vec.set_len(num_read) };
        Ok(vec)
    }

    fn write(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _data: Vec<u8>, _flags: u32) -> ResultWrite {
        assert!(_data.len() <= u32::max_value() as usize);
        _fl.write_at(_data.as_slice(), _offset).map(|x| x as u32)
    }

    fn fsync(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _datasync: bool) -> ResultEmpty {
        _fl.flush()
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Amos Onn.
//
// 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.
//

use std::ffi::OsStr;
use std::path::Path;
use libc;

use super::fusefl::*;
use fuse_mt::*;
use super::Result;

pub trait ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>;
}

pub trait WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>;

    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

pub enum NoFile {}

#[allow(unused_variables)]
impl ReadFileLike for NoFile {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }
}

#[allow(unused_variables)]
impl WriteFileLike for NoFile {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }

    fn flush(&self) -> Result<()> {
        Err(libc::ENOSYS)
    }
}

pub struct ReadWriteAdaptor<R, W> {
    reader: R,
    writer: W,
}

impl<R, W> ReadFileLike for ReadWriteAdaptor<R, W> where R: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        self.reader.read_at(buf, offset)
    }
}

impl<R, W> WriteFileLike for ReadWriteAdaptor<R, W> where W: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        self.writer.write_at(buf, offset)
    }

    fn flush(&self) -> Result<()> {
        self.writer.flush()
    }
}

pub enum ModalFileLike<R, W, RW> {
    ReadOnly(R),
    WriteOnly(W),
    ReadWrite(RW),
}

use self::ModalFileLike::*;

impl<R, W, RW> ReadFileLike for ModalFileLike<R, W, RW> where
    R: ReadFileLike, RW: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(ref r) => r.read_at(buf, offset),
            WriteOnly(_) => Err(libc::EBADF),
            ReadWrite(ref rw) => rw.read_at(buf, offset),
        }
    }
}

impl<R, W, RW> WriteFileLike for ModalFileLike<R, W, RW> where
    W: WriteFileLike, RW: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.write_at(buf, offset),
            ReadWrite(ref rw) => rw.write_at(buf, offset),
        }
    }

    fn flush(&self) -> Result<()> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.flush(),
            ReadWrite(ref rw) => rw.flush(),
        }
    }
}

pub trait FilesystemFLRwOpen {
    type ReadLike: ReadFileLike; // = NoFile;
    type WriteLike: WriteFileLike; // = NoFile;
    type ReadWriteLike: ReadFileLike+WriteFileLike; // = ReadWriteAdaptor<Self::ReadLike, Self::WriteLike>;

    fn open_read(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn open_write(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn open_readwrite(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_read(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn create_write(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_readwrite(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
pub trait FilesystemFLOpen {
    type FileLike: ReadFileLike+WriteFileLike;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    fn read(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _size: u32) -> ResultData {
        let _size = _size as usize;
        let mut vec = Vec::<u8>::with_capacity(_size);
        unsafe { vec.set_len(_size) };
        let num_read = _fl.read_at(vec.as_mut_slice(), _offset)?;
        assert!(num_read <= _size);
        unsafe { vec.set_len(num_read) };
        Ok(vec)
    }

    fn write(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _data: Vec<u8>, _flags: u32) -> ResultWrite {
        assert!(_data.len() <= u32::max_value() as usize);
        _fl.write_at(_data.as_slice(), _offset).map(|x| x as u32)
    }

    fn fsync(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _datasync: bool) -> ResultEmpty {
        _fl.flush()
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
impl<T> FilesystemFLOpen for T where T: FilesystemFLRwOpen {
    type FileLike = ModalFileLike<
        <Self as FilesystemFLRwOpen>::ReadLike,
        <Self as FilesystemFLRwOpen>::WriteLike,
        <Self as FilesystemFLRwOpen>::ReadWriteLike,
    >;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_open(self.open_read(_req, _path, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_open(self.open_write(_req, _path, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_open(self.open_readwrite(_req, _path, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_create(self.create_read(_req, _parent, _name, _mode, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_create(self.create_write(_req, _parent, _name, _mode, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_create(self.create_readwrite(_req, _parent, _name, _mode, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }
}

<commit_msg>Added impl of {Read,Write}FileLike for File.<commit_after>// Copyright 2017 Amos Onn.
//
// 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.
//

use std::fs::File;
use std::os::unix::fs::FileExt;
use std::ffi::OsStr;
use std::path::Path;
use libc;

use super::fusefl::*;
use fuse_mt::*;
use super::Result;

pub trait ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>;
}

pub trait WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>;

    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

impl ReadFileLike for File {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        FileExt::read_at(self, buf, offset).map_err(|x| x.raw_os_error().unwrap())
    }
}

impl WriteFileLike for File {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        FileExt::write_at(self, buf, offset).map_err(|x| x.raw_os_error().unwrap())
    }

    // NOTE: we can't use the flush method from Write, because that wants a &mut. However, for now
    // File's impl of flush is the same as ours, Ok(()), so we can stick with that.
    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

pub enum NoFile {}

#[allow(unused_variables)]
impl ReadFileLike for NoFile {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }
}

#[allow(unused_variables)]
impl WriteFileLike for NoFile {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }

    fn flush(&self) -> Result<()> {
        Err(libc::ENOSYS)
    }
}

pub struct ReadWriteAdaptor<R, W> {
    reader: R,
    writer: W,
}

impl<R, W> ReadFileLike for ReadWriteAdaptor<R, W> where R: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        self.reader.read_at(buf, offset)
    }
}

impl<R, W> WriteFileLike for ReadWriteAdaptor<R, W> where W: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        self.writer.write_at(buf, offset)
    }

    fn flush(&self) -> Result<()> {
        self.writer.flush()
    }
}

pub enum ModalFileLike<R, W, RW> {
    ReadOnly(R),
    WriteOnly(W),
    ReadWrite(RW),
}

use self::ModalFileLike::*;

impl<R, W, RW> ReadFileLike for ModalFileLike<R, W, RW> where
    R: ReadFileLike, RW: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(ref r) => r.read_at(buf, offset),
            WriteOnly(_) => Err(libc::EBADF),
            ReadWrite(ref rw) => rw.read_at(buf, offset),
        }
    }
}

impl<R, W, RW> WriteFileLike for ModalFileLike<R, W, RW> where
    W: WriteFileLike, RW: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.write_at(buf, offset),
            ReadWrite(ref rw) => rw.write_at(buf, offset),
        }
    }

    fn flush(&self) -> Result<()> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.flush(),
            ReadWrite(ref rw) => rw.flush(),
        }
    }
}

pub trait FilesystemFLRwOpen {
    type ReadLike: ReadFileLike; // = NoFile;
    type WriteLike: WriteFileLike; // = NoFile;
    type ReadWriteLike: ReadFileLike+WriteFileLike; // = ReadWriteAdaptor<Self::ReadLike, Self::WriteLike>;

    fn open_read(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn open_write(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn open_readwrite(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_read(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn create_write(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_readwrite(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
pub trait FilesystemFLOpen {
    type FileLike: ReadFileLike+WriteFileLike;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    fn read(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _size: u32) -> ResultData {
        let _size = _size as usize;
        let mut vec = Vec::<u8>::with_capacity(_size);
        unsafe { vec.set_len(_size) };
        let num_read = _fl.read_at(vec.as_mut_slice(), _offset)?;
        assert!(num_read <= _size);
        unsafe { vec.set_len(num_read) };
        Ok(vec)
    }

    fn write(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _data: Vec<u8>, _flags: u32) -> ResultWrite {
        assert!(_data.len() <= u32::max_value() as usize);
        _fl.write_at(_data.as_slice(), _offset).map(|x| x as u32)
    }

    fn fsync(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _datasync: bool) -> ResultEmpty {
        _fl.flush()
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
impl<T> FilesystemFLOpen for T where T: FilesystemFLRwOpen {
    type FileLike = ModalFileLike<
        <Self as FilesystemFLRwOpen>::ReadLike,
        <Self as FilesystemFLRwOpen>::WriteLike,
        <Self as FilesystemFLRwOpen>::ReadWriteLike,
    >;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_open(self.open_read(_req, _path, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_open(self.open_write(_req, _path, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_open(self.open_readwrite(_req, _path, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_create(self.create_read(_req, _parent, _name, _mode, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_create(self.create_write(_req, _parent, _name, _mode, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_create(self.create_readwrite(_req, _parent, _name, _mode, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }
}

<|endoftext|>


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

use reqwest::blocking::{Client, ClientBuilder};
use reqwest::header::*;
use std::io::Read;

use crate::REFERER as REF;
use crate::USER_AGENT as UA;

use crate::error::Error;

lazy_static! {
    static ref CLIENT: Client = { ClientBuilder::new().gzip(true).build().unwrap() };
}

/// Header type for get requests
pub enum HeaderType {
    /// Html browser request
    Html,
    /// Ajax js request
    Ajax,
}

/// Does a get request under the provided url
/// The header varies by the provided HeaderType
pub fn get(url: &str, htype: HeaderType) -> Result<String, Error> {
    trace!("Starting downloading {}", url);

    let mut res = CLIENT.get(url).headers(header(htype)).send()?;

    debug!("Response header: {:?}", res.headers());
    debug!("Response status: {:?}", res.status());
    debug!("Final URL: {:?}", res.headers().get(LOCATION));
    trace!("DEV header: {:?}", res.headers().get(CONTENT_ENCODING));
    let mut body = String::new();
    res.read_to_string(&mut body)?;
    Ok(body)
}

/// Construct a header
/// This function does not check for errors and is
/// verified by the tests
fn header(htype: HeaderType) -> HeaderMap {
    let mut headers = HeaderMap::new();

    headers.insert(ACCEPT_ENCODING, "gzip, deflate".parse().unwrap());

    //headers.insert(PRAGMA, "no-cache".parse().unwrap());
    headers.insert(ACCEPT_LANGUAGE, "en-US,en;q=0.5".parse().unwrap());
    headers.insert(USER_AGENT, UA.parse().unwrap());
    headers.insert(REFERER, REF.parse().unwrap());
    headers.insert(CACHE_CONTROL, "max-age=0".parse().unwrap());

    match htype {
        HeaderType::Html => {
            headers.insert(
                ACCEPT,
                "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
                    .parse()
                    .unwrap(),
            );
        }
        HeaderType::Ajax => {
            headers.insert(ACCEPT, "application/json, text/plain, */*".parse().unwrap());
        }
    }

    trace!("Generated headers: {:?}", headers);
    headers
}

#[cfg(test)]
mod test {
    use super::header;
    use super::*;

    /// Test header creation
    #[test]
    fn header_test() {
        let _ = header(HeaderType::Html);
        let _ = header(HeaderType::Ajax);
    }

    /// Test a html get request
    #[test]
    fn get_html_gzipped() {
        let b_html: String = get("https://httpbin.org/gzip", HeaderType::Html).unwrap();
        assert!(true, b_html.contains(r#""gzipped": true"#));
    }

    /// Test a ajax json get request
    #[test]
    fn get_ajax() {
        let b_ajax = get("https://httpbin.org/user-agent", HeaderType::Ajax).unwrap();
        assert!(b_ajax.contains(UA));
    }

    /// Run z8 test
    #[test]
    fn get_ajax_z8() {
        let b_ajax = get("http://crossfire.z8games.com/clan/1", HeaderType::Ajax).unwrap();
        assert!(b_ajax.contains("Clan1"));
    }

    #[test]
    fn get_ajax_z8_member() {
        let b_ajax = get("http://crossfire.z8games.com/rest/clanmembers.json?clanID=68910&page=1&perPage=10&rankType=user", HeaderType::Ajax).unwrap();
        assert!(b_ajax.contains("Dr.Alptraum"));
        println!("{}", b_ajax);
    }
}
<commit_msg>Ignore z8 tests due to slow reponse times<commit_after>// Copyright 2017-2020 Aron Heinecke
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use reqwest::blocking::{Client, ClientBuilder};
use reqwest::header::*;
use std::io::Read;

use crate::REFERER as REF;
use crate::USER_AGENT as UA;

use crate::error::Error;

lazy_static! {
    static ref CLIENT: Client = { ClientBuilder::new().gzip(true).build().unwrap() };
}

/// Header type for get requests
pub enum HeaderType {
    /// Html browser request
    Html,
    /// Ajax js request
    Ajax,
}

/// Does a get request under the provided url
/// The header varies by the provided HeaderType
pub fn get(url: &str, htype: HeaderType) -> Result<String, Error> {
    trace!("Starting downloading {}", url);

    let mut res = CLIENT.get(url).headers(header(htype)).send()?;

    debug!("Response header: {:?}", res.headers());
    debug!("Response status: {:?}", res.status());
    debug!("Final URL: {:?}", res.headers().get(LOCATION));
    trace!("DEV header: {:?}", res.headers().get(CONTENT_ENCODING));
    let mut body = String::new();
    res.read_to_string(&mut body)?;
    Ok(body)
}

/// Construct a header
/// This function does not check for errors and is
/// verified by the tests
fn header(htype: HeaderType) -> HeaderMap {
    let mut headers = HeaderMap::new();

    headers.insert(ACCEPT_ENCODING, "gzip, deflate".parse().unwrap());

    //headers.insert(PRAGMA, "no-cache".parse().unwrap());
    headers.insert(ACCEPT_LANGUAGE, "en-US,en;q=0.5".parse().unwrap());
    headers.insert(USER_AGENT, UA.parse().unwrap());
    headers.insert(REFERER, REF.parse().unwrap());
    headers.insert(CACHE_CONTROL, "max-age=0".parse().unwrap());

    match htype {
        HeaderType::Html => {
            headers.insert(
                ACCEPT,
                "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
                    .parse()
                    .unwrap(),
            );
        }
        HeaderType::Ajax => {
            headers.insert(ACCEPT, "application/json, text/plain, */*".parse().unwrap());
        }
    }

    trace!("Generated headers: {:?}", headers);
    headers
}

#[cfg(test)]
mod test {
    use super::header;
    use super::*;

    /// Test header creation
    #[test]
    fn header_test() {
        let _ = header(HeaderType::Html);
        let _ = header(HeaderType::Ajax);
    }

    /// Test a html get request
    #[test]
    fn get_html_gzipped() {
        let b_html: String = get("https://httpbin.org/gzip", HeaderType::Html).unwrap();
        assert!(true, b_html.contains(r#""gzipped": true"#));
    }

    /// Test a ajax json get request
    #[test]
    fn get_ajax() {
        let b_ajax = get("https://httpbin.org/user-agent", HeaderType::Ajax).unwrap();
        assert!(b_ajax.contains(UA));
    }

    /// Run z8 test
    #[test]
    #[ignore]
    fn get_ajax_z8() {
        let b_ajax = get("http://crossfire.z8games.com/clan/1", HeaderType::Ajax).unwrap();
        assert!(b_ajax.contains("Clan1"));
    }

    #[test]
    #[ignore]
    fn get_ajax_z8_member() {
        let b_ajax = get("http://crossfire.z8games.com/rest/clanmembers.json?clanID=68910&page=1&perPage=10&rankType=user", HeaderType::Ajax).unwrap();
        assert!(b_ajax.contains("Dr.Alptraum"));
        println!("{}", b_ajax);
    }
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate glib;

use std::rc::{Rc, Weak};
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};

use gtk::prelude::*;
use gtk::{ApplicationWindow, HeaderBar, Button,
          FileChooserDialog, ResponseType, FileChooserAction};

use ::media::{Context, ContextMessage};
use ::media::ContextMessage::*;

use super::{AudioController, InfoController, MediaHandler, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: AudioController,

    ctx: Option<Context>,
    has_init: bool,

    self_weak: Option<Weak<RefCell<MainController>>>,
    listener_src: Option<glib::SourceId>
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let mc = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),
            ctx: None,
            has_init: false,
            self_weak: None,
            listener_src: None,
        }));

        {
            // TODO: stop any playing context or pending_ctx
            let mut mc_mut = mc.borrow_mut();
            mc_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            mc_mut.window.set_titlebar(&mc_mut.header_bar);

            let mc_weak = Rc::downgrade(&mc);
            mc_mut.self_weak = Some(mc_weak);
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let mc_weak = Rc::downgrade(&mc);
        open_btn.connect_clicked(move |_|
            match mc_weak.upgrade() {
                Some(mc) => {
                    mc.borrow().stop();
                    mc.borrow_mut().select_media();
                },
                None => panic!("Main controller is no longer available for select_media"),
            }
        );

        mc
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn stop(&self) {
        if let Some(context) = self.ctx.as_ref() {
            context.stop();
            if let Some(source_id) = self.listener_src {
                // remove listerner in order to avoid conflict on borrowing of self
                glib::source_remove(source_id);
            }
        }
    }

    fn process_message(&mut self,
        message: ContextMessage,
        ui_tx_opt: Option<&Sender<ContextMessage>>
    ) -> bool
    {
        let mut keep_going = true;
        match message {
            AsyncDone => {
                println!("Received AsyncDone");

                if !self.has_init {
                    let ref context = self.ctx.as_ref()
                        .expect("Received AsyncDone, but context is not available");

                    self.info_ctrl.new_media(context);
                    self.video_ctrl.new_media(context);
                    self.audio_ctrl.new_media(context);

                    self.header_bar.set_subtitle(Some(context.file_name.as_str()));

                    self.has_init = true;
                }
            },
            Eos => {
                println!("Received Eos");
                keep_going = false;
            },
            FailedToOpenMedia => {
                eprintln!("ERROR: failed to open media");
                self.ctx = None;
                // TODO: clear UI
                keep_going = false;
            },
            HaveAudioBuffer(buffer) => {
                println!("Received HaveAudioBuffer");
                /*println!("Received AudioBuffer with offset: {}, pts: {:?}, dts: {:?}, duration: {:?}",
                    buffer.get_offset(), buffer.get_pts(),
                    buffer.get_dts(), buffer.get_duration()
                );*/
            },
            HaveVideoWidget(video_widget) => {
                println!("Received HaveVideoWidget");
                let ui_tx = ui_tx_opt.as_ref()
                    .expect("Received HaveVideoWidget, but no ui_tx is defined");
                self.video_ctrl.have_widget(video_widget);
                ui_tx.send(GotVideoWidget)
                    .expect("Failed to send GotVideoWidget to context");
            },
            _ => {
                eprintln!("Received an unexpected message => will quit listner");
                keep_going = false;
            },
        };

        if !keep_going {
            self.listener_src = None;
        }

        keep_going
    }

    fn select_media(&mut self) {
        let file_dlg = FileChooserDialog::new(Some("Open a media file"),
                                              Some(&self.window),
                                              FileChooserAction::Open,
            );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        let result = file_dlg.run();

        // Note: couldn't find a way to coerce ResponseType to i32 in a match statement
        if result == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }
        else {
            ()
        }

        file_dlg.close();
    }

    fn register_listener(&mut self,
        ui_rx: Receiver<ContextMessage>,
        timeout: u32,
        ui_tx_opt: Option<Sender<ContextMessage>>,
    )
    {
        if let Some(ref self_weak) = self.self_weak {
            let self_weak = self_weak.clone();

            let source_id = gtk::timeout_add(timeout, move || {
                let mut keep_going = true;
                let mut msg_iter = ui_rx.try_iter();
                let first_msg_opt = msg_iter.next();
                match first_msg_opt {
                    Some(first_msg) => {
                        // only get mc as mut if a message is received
                        match self_weak.upgrade() {
                            Some(mc) => {
                                let mut mc_mut = mc.borrow_mut();
                                keep_going = mc_mut.process_message(first_msg, ui_tx_opt.as_ref());
                                if keep_going {
                                    // process remaining messages
                                    for msg in msg_iter {
                                        keep_going = mc_mut.process_message(msg, ui_tx_opt.as_ref());
                                        if !keep_going { break; }
                                    }
                                }
                            },
                            None => panic!("Main controller is no longer available for ctx channel listener"),
                        };
                    },
                    None => (),
                };

                if !keep_going { println!("Exiting listener"); }
                glib::Continue(keep_going)
            });

            self.listener_src =Some(source_id);
        }
        // FIXME: else use proper expression to panic!
    }

    fn open_media(&mut self, filepath: PathBuf) {
        let (ctx_tx, ui_rx) = channel();
        let (ui_tx, ctx_rx) = channel();

        self.register_listener(ui_rx, 100, Some(ui_tx));

        match Context::open_media_path(filepath, ctx_tx, ctx_rx) {
            Ok(ctx) => {
                self.has_init = false;
                self.ctx = Some(ctx);
            },
            Err(error) => println!("Error opening media: {}", error),
        };
    }
}
<commit_msg>Futureproof sequence for stopping media (#7)<commit_after>extern crate gtk;
extern crate glib;

use std::rc::{Rc, Weak};
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};

use gtk::prelude::*;
use gtk::{ApplicationWindow, HeaderBar, Button,
          FileChooserDialog, ResponseType, FileChooserAction};

use ::media::{Context, ContextMessage};
use ::media::ContextMessage::*;

use super::{AudioController, InfoController, MediaHandler, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: AudioController,

    ctx: Option<Context>,
    has_init: bool,

    self_weak: Option<Weak<RefCell<MainController>>>,
    listener_src: Option<glib::SourceId>
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let mc = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),
            ctx: None,
            has_init: false,
            self_weak: None,
            listener_src: None,
        }));

        {
            // TODO: stop any playing context or pending_ctx
            let mut mc_mut = mc.borrow_mut();
            mc_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            mc_mut.window.set_titlebar(&mc_mut.header_bar);

            let mc_weak = Rc::downgrade(&mc);
            mc_mut.self_weak = Some(mc_weak);
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let mc_weak = Rc::downgrade(&mc);
        open_btn.connect_clicked(move |_|
            match mc_weak.upgrade() {
                Some(mc) => {
                    mc.borrow_mut().select_media();
                },
                None => panic!("Main controller is no longer available for select_media"),
            }
        );

        mc
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn stop(&mut self) {
        if let Some(context) = self.ctx.as_ref() {
            context.stop();
            if let Some(source_id) = self.listener_src {
                // remove listerner in order to avoid conflict on borrowing of self
                glib::source_remove(source_id);
            }
            self.listener_src = None;
        }
    }

    fn process_message(&mut self,
        message: ContextMessage,
        ui_tx_opt: Option<&Sender<ContextMessage>>
    ) -> bool
    {
        let mut keep_going = true;
        match message {
            AsyncDone => {
                println!("Received AsyncDone");

                if !self.has_init {
                    let ref context = self.ctx.as_ref()
                        .expect("Received AsyncDone, but context is not available");

                    self.info_ctrl.new_media(context);
                    self.video_ctrl.new_media(context);
                    self.audio_ctrl.new_media(context);

                    self.header_bar.set_subtitle(Some(context.file_name.as_str()));

                    self.has_init = true;
                }
            },
            Eos => {
                println!("Received Eos");
                keep_going = false;
            },
            FailedToOpenMedia => {
                eprintln!("ERROR: failed to open media");
                self.ctx = None;
                // TODO: clear UI
                keep_going = false;
            },
            HaveAudioBuffer(buffer) => {
                //println!("Received HaveAudioBuffer");
                /*println!("Received AudioBuffer with offset: {}, pts: {:?}, dts: {:?}, duration: {:?}",
                    buffer.get_offset(), buffer.get_pts(),
                    buffer.get_dts(), buffer.get_duration()
                );*/
            },
            HaveVideoWidget(video_widget) => {
                //println!("Received HaveVideoWidget");
                let ui_tx = ui_tx_opt.as_ref()
                    .expect("Received HaveVideoWidget, but no ui_tx is defined");
                self.video_ctrl.have_widget(video_widget);
                ui_tx.send(GotVideoWidget)
                    .expect("Failed to send GotVideoWidget to context");
            },
            _ => {
                eprintln!("Received an unexpected message => will quit listner");
                keep_going = false;
            },
        };

        if !keep_going {
            self.listener_src = None;
        }

        keep_going
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = FileChooserDialog::new(Some("Open a media file"),
                                              Some(&self.window),
                                              FileChooserAction::Open,
            );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        let result = file_dlg.run();

        // Note: couldn't find a way to coerce ResponseType to i32 in a match statement
        if result == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }
        else {
            ()
        }

        file_dlg.close();
    }

    fn register_listener(&mut self,
        ui_rx: Receiver<ContextMessage>,
        timeout: u32,
        ui_tx_opt: Option<Sender<ContextMessage>>,
    )
    {
        if let Some(ref self_weak) = self.self_weak {
            let self_weak = self_weak.clone();

            let source_id = gtk::timeout_add(timeout, move || {
                let mut keep_going = true;
                let mut msg_iter = ui_rx.try_iter();
                let first_msg_opt = msg_iter.next();
                match first_msg_opt {
                    Some(first_msg) => {
                        // only get mc as mut if a message is received
                        match self_weak.upgrade() {
                            Some(mc) => {
                                let mut mc_mut = mc.borrow_mut();
                                keep_going = mc_mut.process_message(first_msg, ui_tx_opt.as_ref());
                                if keep_going {
                                    // process remaining messages
                                    for msg in msg_iter {
                                        keep_going = mc_mut.process_message(msg, ui_tx_opt.as_ref());
                                        if !keep_going { break; }
                                    }
                                }
                            },
                            None => panic!("Main controller is no longer available for ctx channel listener"),
                        };
                    },
                    None => (),
                };

                if !keep_going { println!("Exiting listener"); }
                glib::Continue(keep_going)
            });

            self.listener_src =Some(source_id);
        }
        // FIXME: else use proper expression to panic!
    }

    fn open_media(&mut self, filepath: PathBuf) {
        let (ctx_tx, ui_rx) = channel();
        let (ui_tx, ctx_rx) = channel();

        self.register_listener(ui_rx, 100, Some(ui_tx));

        match Context::open_media_path(filepath, ctx_tx, ctx_rx) {
            Ok(ctx) => {
                self.has_init = false;
                self.ctx = Some(ctx);
            },
            Err(error) => println!("Error opening media: {}", error),
        };
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An example of using simplex noise

#![feature(macro_rules)]

extern crate noise;

use noise::{simplex2, Seed, Point2};

mod debug {
    pub mod image;
}

fn main() {
    debug::image::render_to_png("simplex2.png", &Seed::new(0), 256, 256, scaled_simplex2);
    println!("\nGenerated simplex2.png, simplex3.png and simplex4.png");
}

fn scaled_simplex2(seed: &Seed, point: &Point2<f32>) -> f32 {
    return simplex2(seed, &[point[0] / 32.0, point[1] / 32.00]);
}
<commit_msg>Simplex example no longer lists files that aren't generated.<commit_after>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An example of using simplex noise

#![feature(macro_rules)]

extern crate noise;

use noise::{simplex2, Seed, Point2};

mod debug {
    pub mod image;
}

fn main() {
    debug::image::render_to_png("simplex2.png", &Seed::new(0), 256, 256, scaled_simplex2);
    println!("\nGenerated simplex2.png");
}

fn scaled_simplex2(seed: &Seed, point: &Point2<f32>) -> f32 {
    return simplex2(seed, &[point[0] / 32.0, point[1] / 32.00]);
}
<|endoftext|>


<commit_before>use super::moves::Plies;
use super::square::{File, Rank, Square};
use super::pos::{Position, Kingside, Queenside};
use super::piece;
use super::color::Color;

use std::collections::HashMap;

pub fn start_pos() -> Position {
    fen_to_position("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap()
}

pub fn fen_to_position(fen: &str) -> Result<Position, &str> {
    let fields: Vec<&str> = fen.split(' ').collect();
    if fields.len() < 6 {
        return Err("Not enough fields in FEN input.");
    };
    let mut pos_str = "".to_string();
    for ch in fields[0].chars() {
        match ch {
            '0' ... '9' => {
                for _ in range(0, ch as uint - '0' as uint) {
                    pos_str.push('1')
                }
            }
            _ => pos_str.push(ch)
        }
    }
    let mut pos = Position::new();
    let (mut rank, mut file) = (7, 0);
    let mut decode = HashMap::new();
    decode.insert('P', piece::WP);
    decode.insert('K', piece::WK);
    decode.insert('Q', piece::WQ);
    decode.insert('B', piece::WB);
    decode.insert('N', piece::WN);
    decode.insert('R', piece::WR);
    decode.insert('p', piece::BP);
    decode.insert('k', piece::BK);
    decode.insert('q', piece::BQ);
    decode.insert('b', piece::BB);
    decode.insert('n', piece::BN);
    decode.insert('r', piece::BR);
    for ch in fields[0].chars() {
        if ch == '/' {
            rank = rank - 1;
            file = 0;
        } else {
            match decode.get(&ch) {
                None => return Err("Unexpected charactor found."),
                Some(val) => {
                    pos.set_at_mut(Square::new(File(file),Rank(rank)), *val);
                    file = file + 1;
                }
            }
        }
    }
    let side_to_move = fields[1].char_at(0);
    match side_to_move {
        'w' => pos.set_side_to_move_mut(Color::White),
        'b' => pos.set_side_to_move_mut(Color::Black),
        _ => return Err("Invalid side to move."),
    };
    let castle = fields[2];
    pos.set_castle_mut(Kingside,  Color::White, castle.char_at(0) == 'K');
    pos.set_castle_mut(Queenside, Color::White, castle.char_at(1) == 'Q');
    pos.set_castle_mut(Kingside,  Color::Black, castle.char_at(2) == 'k');
    pos.set_castle_mut(Queenside, Color::Black, castle.char_at(3) == 'q');
    let en_passant_char = fields[3].char_at(0);
    if en_passant_char != '-' {
        pos.set_en_passant_mut(Some(File(en_passant_char as u8 - 'a' as u8)));
    }
    match fields[4].parse::<u8>() {
        None => return Err("Invalid number of plies."),
        Some(val) => pos.set_ply_count_mut(Plies(val)),
    }
    Ok(pos)
}
<commit_msg>Bug fix in "fen_to_position()".<commit_after>use super::moves::Plies;
use super::square::{File, Rank, Square};
use super::pos::{Position, Kingside, Queenside};
use super::piece;
use super::color::Color;

use std::collections::HashMap;

pub fn start_pos() -> Position {
    fen_to_position("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap()
}

pub fn fen_to_position(fen: &str) -> Result<Position, &str> {
    let fields: Vec<&str> = fen.split(' ').collect();
    if fields.len() < 6 {
        return Err("Not enough fields in FEN input.");
    };
    let mut pos_str = "".to_string();
    for ch in fields[0].chars() {
        match ch {
            '0' ... '9' => {
                for _ in range(0, ch as uint - '0' as uint) {
                    pos_str.push('1')
                }
            }
            _ => pos_str.push(ch)
        }
    }
    let mut pos = Position::new();
    let (mut rank, mut file) = (7, 0);
    let mut decode = HashMap::new();
    decode.insert('P', piece::WP);
    decode.insert('K', piece::WK);
    decode.insert('Q', piece::WQ);
    decode.insert('B', piece::WB);
    decode.insert('N', piece::WN);
    decode.insert('R', piece::WR);
    decode.insert('p', piece::BP);
    decode.insert('k', piece::BK);
    decode.insert('q', piece::BQ);
    decode.insert('b', piece::BB);
    decode.insert('n', piece::BN);
    decode.insert('r', piece::BR);
    for ch in pos_str.chars() {
        if ch == '/' {
            rank = rank - 1;
            file = 0;
        } else if ch == '1' {
            file = file + 1;
        } else {
            match decode.get(&ch) {
                None => return Err("Unexpected charactor found."),
                Some(val) => {
                    pos.set_at_mut(Square::new(File(file),Rank(rank)), *val);
                    file = file + 1;
                }
            }
        }
    }
    let side_to_move = fields[1].char_at(0);
    match side_to_move {
        'w' => pos.set_side_to_move_mut(Color::White),
        'b' => pos.set_side_to_move_mut(Color::Black),
        _ => return Err("Invalid side to move."),
    };
    let castle = fields[2];
    pos.set_castle_mut(Kingside,  Color::White, castle.char_at(0) == 'K');
    pos.set_castle_mut(Queenside, Color::White, castle.char_at(1) == 'Q');
    pos.set_castle_mut(Kingside,  Color::Black, castle.char_at(2) == 'k');
    pos.set_castle_mut(Queenside, Color::Black, castle.char_at(3) == 'q');
    let en_passant_char = fields[3].char_at(0);
    if en_passant_char != '-' {
        pos.set_en_passant_mut(Some(File(en_passant_char as u8 - 'a' as u8)));
    }
    match fields[4].parse::<u8>() {
        None => return Err("Invalid number of plies."),
        Some(val) => pos.set_ply_count_mut(Plies(val)),
    }
    Ok(pos)
}
<|endoftext|>