<commit_before>use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
use core::marker::PhantomData;
use core::mem;
use super::BrotliAlloc;
use super::encode::{
  BrotliEncoderOperation,
  BrotliEncoderCreateInstance,
  BrotliEncoderSetCustomDictionary,
  BrotliEncoderDestroyInstance,
  BrotliEncoderMaxCompressedSize,
  BrotliEncoderCompressStream,
};
use core::ops::Range;
use super::backward_references::BrotliEncoderParams;
pub trait Joinable<T:Send+'static, U:Send+'static>:Sized {
  fn join(self) -> Result<T, U>;
}

pub struct CompressionThreadResult<Alloc:BrotliAlloc+Send+'static> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  compressed: <Alloc as Allocator<u8>>::AllocatedMemory,
  compressed_size: usize,
  alloc: Alloc,
}
enum InternalSendAlloc<T:Send+'static, Alloc:BrotliAlloc+Send+'static, Join: Joinable<T, Alloc>>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  A(Alloc),
  Join(Join),
  SpawningOrJoining(PhantomData<T>),
}
pub struct SendAlloc<T:Send+'static,
                     Alloc:BrotliAlloc +Send+'static,
                     Join:Joinable<T, Alloc>>(InternalSendAlloc<T, Alloc, Join>)
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send;

impl<T:Send+'static, Alloc:BrotliAlloc+Send+'static,Join:Joinable<T, Alloc>> SendAlloc<T, Alloc, Join>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  pub fn new(alloc: Alloc) -> Self {
    SendAlloc::<T, Alloc, Join>(InternalSendAlloc::A(alloc))
  }
  pub fn unwrap_or(self, other: Alloc) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::SpawningOrJoining(_) | InternalSendAlloc::Join(_) => {
        other
      },
    }
  }
  pub fn unwrap(self) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::SpawningOrJoining(_) | InternalSendAlloc::Join(_) => panic!("Item permanently borrowed/leaked"),
    }
  }
}

enum InternalOwned<T> {
  Item(T),
  Borrowed,
}

pub struct Owned<T>(InternalOwned<T>);
impl<T> Owned<T> {
  pub fn new(data:T) -> Self {
    Owned::<T>(InternalOwned::Item(data))
  }
  pub fn unwrap_or(self, other: T) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      other
    }
  }
  pub fn unwrap(self) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      panic!("Item permanently borrowed")
    }
  }
}

pub trait OwnedRetriever<U:Send+'static> {
  fn view(&self) -> &U;
  fn unwrap(self) -> U;
}

pub trait BatchSpawnable<T:Send+'static,
                         Alloc:BrotliAlloc+Send+'static,
                         U:Send+'static>
  where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static
{
  type JoinHandle: Joinable<T, Alloc>;
  type FinalJoinHandle: OwnedRetriever<U>;
  // this function takes in an input slice
  // a SendAlloc per thread and converts them all into JoinHandle
  // the input is borrowed until the joins complete
  // owned is set to borrowed
  // the final join handle is a r/w lock which will return the SliceW to the owner
  // the FinalJoinHandle is only to be called when each individual JoinHandle has been examined
  // the function is called with the thread_index, the num_threads, a reference to the slice under a read lock,
  // and an allocator from the alloc_per_thread
  fn batch_spawn<F: Fn(usize, usize, &U, Alloc) -> T>(
    &mut self,
    input: &mut Owned<U>,
    alloc_per_thread:&mut [SendAlloc<T, Alloc, Self::JoinHandle>],
    f: F,
  ) -> Self::FinalJoinHandle;
}

pub fn CompressMultiSlice<Alloc:BrotliAlloc+Send+'static,
                          Spawner:BatchSpawnable<CompressionThreadResult<Alloc>,
                                                 Alloc,
                                                 (<Alloc as Allocator<u8>>::AllocatedMemory, BrotliEncoderParams)>> (
  params:&BrotliEncoderParams,
  input_slice: &[u8],
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>, Alloc, Spawner::JoinHandle>],
  mut thread_spawner: Spawner,
) -> Result<usize, ()> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  let input = if let InternalSendAlloc::A(ref mut alloc) = alloc_per_thread[0].0 {
    let mut input = <Alloc as Allocator<u8>>::alloc_cell(alloc, input_slice.len());
    input.slice_mut().clone_from_slice(input_slice);
    input
  } else {
    <Alloc as Allocator<u8>>::AllocatedMemory::default()
  };
  let mut owned_input = Owned::new(input);
  let ret = CompressMulti(params, &mut owned_input, output, alloc_per_thread,thread_spawner);
  if let InternalSendAlloc::A(ref mut alloc) = alloc_per_thread[0].0 {
    <Alloc as Allocator<u8>>::free_cell(alloc, owned_input.unwrap());
  }
  ret
}

fn get_range(thread_index: usize, num_threads: usize, file_size: usize) -> Range<usize> {
    ((thread_index * file_size) / num_threads)..(((thread_index + 1) * file_size) / num_threads)
}

fn compress_part<Alloc: BrotliAlloc+Send+'static,
                 SliceW:SliceWrapper<u8>>(
  thread_index: usize,
  num_threads: usize,
  input_and_params:&(SliceW, BrotliEncoderParams),
  mut alloc: Alloc,
) -> CompressionThreadResult<Alloc> where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static {
  let mut range = get_range(thread_index + 1, num_threads + 1, input_and_params.0.len());
  let mut mem = <Alloc as Allocator<u8>>::alloc_cell(&mut alloc,
                                                     BrotliEncoderMaxCompressedSize(range.end - range.start));
  let mut state = BrotliEncoderCreateInstance(alloc);
  state.params = input_and_params.1.clone();
  state.params.catable = true; // make sure we can concatenate this to the other work results
  state.params.appendable = true; // make sure we are at least appendable, so that future items can be catted in
  state.params.magic_number = false; // no reason to pepper this around
  BrotliEncoderSetCustomDictionary(&mut state, range.start, &input_and_params.0.slice()[..range.start]);
  assert_eq!(range.start, 0);
  let mut out_offset = 0usize;
  let mut compression_result = Err(());
  let mut available_out = mem.len();
  loop {
    let mut next_in_offset = 0usize;
    let mut available_in = range.end - range.start;
    let result = BrotliEncoderCompressStream(&mut state,
                                             BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
                                             &mut available_in,
                                             &input_and_params.0.slice()[range.clone()],
                                             &mut next_in_offset,
                                             &mut available_out,
                                             mem.slice_mut(),
                                             &mut out_offset,
                                             &mut None,
                                             &mut |_a,_b,_c,_d|());
    let new_range = range.start + next_in_offset..range.end;
    range = new_range;
    if result != 0 {
      compression_result = Ok(out_offset);
      break;
    } else if available_out == 0 {
      compression_result = Err(()); // mark no space??
      break
    }
  }
  BrotliEncoderDestroyInstance(&mut state);

  CompressionThreadResult::<Alloc>{
    compressed:mem,
    compressed_size:out_offset,
    alloc:state.m8,
  }
}

pub fn CompressMulti<Alloc:BrotliAlloc+Send+'static,
                     SliceW: SliceWrapper<u8>+Send+'static,
                     Spawner:BatchSpawnable<CompressionThreadResult<Alloc>,
                                            Alloc,
                                            (SliceW, BrotliEncoderParams)>> (
  params:&BrotliEncoderParams,
  owned_input: &mut Owned<SliceW>,
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>, Alloc, Spawner::JoinHandle>],
  mut thread_spawner: Spawner,
) -> Result<usize, ()> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
    let num_threads = alloc_per_thread.len();
    let (mut alloc, alloc_rest) = alloc_per_thread.split_at_mut(1);
    let actually_owned_mem = mem::replace(owned_input, Owned(InternalOwned::Borrowed));
    let mut owned_input_pair = Owned::new((actually_owned_mem.unwrap(), params.clone()));
    let mut retrieve_owned_input = thread_spawner.batch_spawn(&mut owned_input_pair, alloc_rest, compress_part);
    let mut compression_result = Err(());
    let mut available_out = output.len();
    {
        let input_and_params = retrieve_owned_input.view();
        let mut state = BrotliEncoderCreateInstance(match mem::replace(&mut alloc[0].0,
                                                                       InternalSendAlloc::SpawningOrJoining(PhantomData::default())) {
            InternalSendAlloc::A(a) => a,
            _ => panic!("all public interfaces which create SendAlloc can only specify subtype A")
        });
        state.params = params.clone();
        state.params.appendable = true; // make sure we are at least appendable, so that future items can be catted in
        let mut range = get_range(0, num_threads, input_and_params.0.len());
        assert_eq!(range.start, 0);
        let mut out_offset = 0usize;
        loop {
            let mut next_in_offset = 0usize;
            let mut available_in = range.end - range.start;
            let result = BrotliEncoderCompressStream(&mut state,
                                                 BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
                                                 &mut available_in,
                                                 &input_and_params.0.slice()[range.clone()],
                                                 &mut next_in_offset,
                                                 &mut available_out,
                                                 output,
                                                 &mut out_offset,
                                                 &mut None,
                                                 &mut |_a,_b,_c,_d|());
            let new_range = range.start + next_in_offset..range.end;
            range = new_range;
            if result != 0 {
                compression_result = Ok(out_offset);
                break;
            } else if available_out == 0 {
                compression_result = Err(()); // mark no space??
                break
            }
        }
        BrotliEncoderDestroyInstance(&mut state);
        alloc[0].0 = InternalSendAlloc::A(state.m8);
    }
    for thread in alloc_rest.iter_mut() {
        let alloc;
        match mem::replace(&mut thread.0, InternalSendAlloc::SpawningOrJoining(PhantomData::default())) {
            InternalSendAlloc::A(_) | InternalSendAlloc::SpawningOrJoining(_) => panic!("Thread not properly spawned"),
            InternalSendAlloc::Join(join) => match join.join() {
                Ok(result) => {
                    alloc = result.alloc;
                },
                Err(allocator) => {
                    alloc = allocator;
                    compression_result = Err(());
                },
            },
        }
        thread.0 = InternalSendAlloc::A(alloc);
    }
    *owned_input = Owned::new(retrieve_owned_input.unwrap().0); // return the input to its rightful owner before returning
    compression_result
}

<commit_msg>it builds...but will it run?<commit_after>use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
use core::marker::PhantomData;
use core::mem;
use super::BrotliAlloc;
use super::encode::{
  BrotliEncoderOperation,
  BrotliEncoderCreateInstance,
  BrotliEncoderSetCustomDictionary,
  BrotliEncoderDestroyInstance,
  BrotliEncoderMaxCompressedSize,
  BrotliEncoderCompressStream,
};
use concat::{
  BroCatli,
  BroCatliResult,
};
use core::ops::Range;
use super::backward_references::BrotliEncoderParams;
pub trait Joinable<T:Send+'static, U:Send+'static>:Sized {
  fn join(self) -> Result<T, U>;
}

pub struct CompressionThreadResult<Alloc:BrotliAlloc+Send+'static> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  compressed: <Alloc as Allocator<u8>>::AllocatedMemory,
  compressed_size: usize,
  alloc: Alloc,
}
enum InternalSendAlloc<T:Send+'static, Alloc:BrotliAlloc+Send+'static, Join: Joinable<T, Alloc>>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  A(Alloc),
  Join(Join),
  SpawningOrJoining(PhantomData<T>),
}
pub struct SendAlloc<T:Send+'static,
                     Alloc:BrotliAlloc +Send+'static,
                     Join:Joinable<T, Alloc>>(InternalSendAlloc<T, Alloc, Join>)
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send;

impl<T:Send+'static, Alloc:BrotliAlloc+Send+'static,Join:Joinable<T, Alloc>> SendAlloc<T, Alloc, Join>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  pub fn new(alloc: Alloc) -> Self {
    SendAlloc::<T, Alloc, Join>(InternalSendAlloc::A(alloc))
  }
  pub fn unwrap_or(self, other: Alloc) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::SpawningOrJoining(_) | InternalSendAlloc::Join(_) => {
        other
      },
    }
  }
  pub fn unwrap(self) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::SpawningOrJoining(_) | InternalSendAlloc::Join(_) => panic!("Item permanently borrowed/leaked"),
    }
  }
}

enum InternalOwned<T> {
  Item(T),
  Borrowed,
}

pub struct Owned<T>(InternalOwned<T>);
impl<T> Owned<T> {
  pub fn new(data:T) -> Self {
    Owned::<T>(InternalOwned::Item(data))
  }
  pub fn unwrap_or(self, other: T) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      other
    }
  }
  pub fn unwrap(self) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      panic!("Item permanently borrowed")
    }
  }
}

pub trait OwnedRetriever<U:Send+'static> {
  fn view(&self) -> &U;
  fn unwrap(self) -> U;
}

pub trait BatchSpawnable<T:Send+'static,
                         Alloc:BrotliAlloc+Send+'static,
                         U:Send+'static>
  where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static
{
  type JoinHandle: Joinable<T, Alloc>;
  type FinalJoinHandle: OwnedRetriever<U>;
  // this function takes in an input slice
  // a SendAlloc per thread and converts them all into JoinHandle
  // the input is borrowed until the joins complete
  // owned is set to borrowed
  // the final join handle is a r/w lock which will return the SliceW to the owner
  // the FinalJoinHandle is only to be called when each individual JoinHandle has been examined
  // the function is called with the thread_index, the num_threads, a reference to the slice under a read lock,
  // and an allocator from the alloc_per_thread
  fn batch_spawn<F: Fn(usize, usize, &U, Alloc) -> T>(
    &mut self,
    input: &mut Owned<U>,
    alloc_per_thread:&mut [SendAlloc<T, Alloc, Self::JoinHandle>],
    f: F,
  ) -> Self::FinalJoinHandle;
}

pub fn CompressMultiSlice<Alloc:BrotliAlloc+Send+'static,
                          Spawner:BatchSpawnable<CompressionThreadResult<Alloc>,
                                                 Alloc,
                                                 (<Alloc as Allocator<u8>>::AllocatedMemory, BrotliEncoderParams)>> (
  params:&BrotliEncoderParams,
  input_slice: &[u8],
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>, Alloc, Spawner::JoinHandle>],
  mut thread_spawner: Spawner,
) -> Result<usize, ()> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  let input = if let InternalSendAlloc::A(ref mut alloc) = alloc_per_thread[0].0 {
    let mut input = <Alloc as Allocator<u8>>::alloc_cell(alloc, input_slice.len());
    input.slice_mut().clone_from_slice(input_slice);
    input
  } else {
    <Alloc as Allocator<u8>>::AllocatedMemory::default()
  };
  let mut owned_input = Owned::new(input);
  let ret = CompressMulti(params, &mut owned_input, output, alloc_per_thread,thread_spawner);
  if let InternalSendAlloc::A(ref mut alloc) = alloc_per_thread[0].0 {
    <Alloc as Allocator<u8>>::free_cell(alloc, owned_input.unwrap());
  }
  ret
}

fn get_range(thread_index: usize, num_threads: usize, file_size: usize) -> Range<usize> {
    ((thread_index * file_size) / num_threads)..(((thread_index + 1) * file_size) / num_threads)
}

fn compress_part<Alloc: BrotliAlloc+Send+'static,
                 SliceW:SliceWrapper<u8>>(
  thread_index: usize,
  num_threads: usize,
  input_and_params:&(SliceW, BrotliEncoderParams),
  mut alloc: Alloc,
) -> CompressionThreadResult<Alloc> where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static {
  let mut range = get_range(thread_index + 1, num_threads + 1, input_and_params.0.len());
  let mut mem = <Alloc as Allocator<u8>>::alloc_cell(&mut alloc,
                                                     BrotliEncoderMaxCompressedSize(range.end - range.start));
  let mut state = BrotliEncoderCreateInstance(alloc);
  state.params = input_and_params.1.clone();
  state.params.catable = true; // make sure we can concatenate this to the other work results
  state.params.appendable = true; // make sure we are at least appendable, so that future items can be catted in
  state.params.magic_number = false; // no reason to pepper this around
  BrotliEncoderSetCustomDictionary(&mut state, range.start, &input_and_params.0.slice()[..range.start]);
  assert_eq!(range.start, 0);
  let mut out_offset = 0usize;
  let mut compression_result = Err(());
  let mut available_out = mem.len();
  loop {
    let mut next_in_offset = 0usize;
    let mut available_in = range.end - range.start;
    let result = BrotliEncoderCompressStream(&mut state,
                                             BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
                                             &mut available_in,
                                             &input_and_params.0.slice()[range.clone()],
                                             &mut next_in_offset,
                                             &mut available_out,
                                             mem.slice_mut(),
                                             &mut out_offset,
                                             &mut None,
                                             &mut |_a,_b,_c,_d|());
    let new_range = range.start + next_in_offset..range.end;
    range = new_range;
    if result != 0 {
      compression_result = Ok(out_offset);
      break;
    } else if available_out == 0 {
      compression_result = Err(()); // mark no space??
      break
    }
  }
  BrotliEncoderDestroyInstance(&mut state);

  CompressionThreadResult::<Alloc>{
    compressed:mem,
    compressed_size:out_offset,
    alloc:state.m8,
  }
}

pub fn CompressMulti<Alloc:BrotliAlloc+Send+'static,
                     SliceW: SliceWrapper<u8>+Send+'static,
                     Spawner:BatchSpawnable<CompressionThreadResult<Alloc>,
                                            Alloc,
                                            (SliceW, BrotliEncoderParams)>> (
  params:&BrotliEncoderParams,
  owned_input: &mut Owned<SliceW>,
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>, Alloc, Spawner::JoinHandle>],
  mut thread_spawner: Spawner,
) -> Result<usize, ()> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
    let num_threads = alloc_per_thread.len();
    let (mut alloc, alloc_rest) = alloc_per_thread.split_at_mut(1);
    let actually_owned_mem = mem::replace(owned_input, Owned(InternalOwned::Borrowed));
    let mut owned_input_pair = Owned::new((actually_owned_mem.unwrap(), params.clone()));
    let mut retrieve_owned_input = thread_spawner.batch_spawn(&mut owned_input_pair, alloc_rest, compress_part);
    let mut compression_result = Err(());
    let output_len = output.len();
    let first_thread_output_max_len = if alloc_rest.len() != 0 { output_len / 2 } else {output.len()};
    let mut available_out = first_thread_output_max_len;
    {
        let first_thread_output = &mut output[output_len - first_thread_output_max_len..];
        let input_and_params = retrieve_owned_input.view();
        let mut state = BrotliEncoderCreateInstance(match mem::replace(&mut alloc[0].0,
                                                                       InternalSendAlloc::SpawningOrJoining(PhantomData::default())) {
            InternalSendAlloc::A(a) => a,
            _ => panic!("all public interfaces which create SendAlloc can only specify subtype A")
        });
        state.params = params.clone();
        state.params.appendable = true; // make sure we are at least appendable, so that future items can be catted in
        let mut range = get_range(0, num_threads, input_and_params.0.len());
        assert_eq!(range.start, 0);
        let mut out_offset = 0usize;
        loop {
            let mut next_in_offset = 0usize;
            let mut available_in = range.end - range.start;
            let result = BrotliEncoderCompressStream(&mut state,
                                                 BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
                                                 &mut available_in,
                                                 &input_and_params.0.slice()[range.clone()],
                                                 &mut next_in_offset,
                                                 &mut available_out,
                                                 first_thread_output,
                                                 &mut out_offset,
                                                 &mut None,
                                                 &mut |_a,_b,_c,_d|());
            let new_range = range.start + next_in_offset..range.end;
            range = new_range;
            if result != 0 {
                compression_result = Ok(out_offset);
                break;
            } else if available_out == 0 {
                compression_result = Err(()); // mark no space??
                break
            }
        }
        BrotliEncoderDestroyInstance(&mut state);
        alloc[0].0 = InternalSendAlloc::A(state.m8);
    }
    let mut bro_cat_li = BroCatli::new();
    if alloc_rest.len() != 0 {
      if let Ok(first_file_size) = compression_result {
        bro_cat_li.new_brotli_file();
        let (cat_output, cat_input) = output.split_at_mut(output_len - first_thread_output_max_len);
        let mut in_offset = 0usize;
        let mut out_offset = 0usize;
        let cat_result = bro_cat_li.stream(&cat_input[..first_file_size],
                                           &mut in_offset,
                                           cat_output,
                                           &mut out_offset);
        if in_offset != first_file_size {
          compression_result = Err(()); // wasn't able to ingest the full file
        }
        match cat_result {
          BroCatliResult::Success | BroCatliResult::NeedsMoreInput  => {
            compression_result = Ok(out_offset);
          },
          BroCatliResult::NeedsMoreOutput => {
            compression_result = Err(()); // not enough space
          },
          _ => {
            compression_result = Err(()); // misc error
          },
        }
      }
    }
    if let Ok(mut out_file_size) = compression_result {
     for thread in alloc_rest.iter_mut() {
       let alloc;
       match mem::replace(&mut thread.0, InternalSendAlloc::SpawningOrJoining(PhantomData::default())) {
         InternalSendAlloc::A(_) | InternalSendAlloc::SpawningOrJoining(_) => panic!("Thread not properly spawned"),
         InternalSendAlloc::Join(join) => match join.join() {
           Ok(mut result) => {
             bro_cat_li.new_brotli_file();
             let mut in_offset = 0usize;
             let cat_result = bro_cat_li.stream(&result.compressed.slice()[..result.compressed_size],
                                                &mut in_offset,
                                                output,
                                                &mut out_file_size);
             match cat_result {
               BroCatliResult::Success | BroCatliResult::NeedsMoreInput  => {
                 compression_result = Ok(out_file_size);
               },
               BroCatliResult::NeedsMoreOutput => {
                 compression_result = Err(()); // not enough space
               }
               _ => {
                 compression_result = Err(()); // misc error
               }
             }
             <Alloc as Allocator<u8>>::free_cell(&mut result.alloc, result.compressed);
             alloc = result.alloc;
           },
           Err(allocator) => {
             alloc = allocator;
             compression_result = Err(());
           },
         },
       }
       thread.0 = InternalSendAlloc::A(alloc);
     }
     if alloc_rest.len() != 0 {
       match bro_cat_li.finish(output, &mut out_file_size) {
         BroCatliResult::Success => compression_result = Ok(out_file_size),
         _ => compression_result = Err(()),
       }
     }
   }

  *owned_input = Owned::new(retrieve_owned_input.unwrap().0); // return the input to its rightful owner before returning
  compression_result
}

<|endoftext|>


<commit_before>use std::{
    collections::{hash_map::RandomState, HashSet},
    path::{Path, PathBuf},
};

use crate::{
    engine::{
        engine::Pool,
        types::{CreateAction, PoolUuid},
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

/// Called when the name of a requested pool coincides with the name of an
/// existing pool. Returns an error if the specifications of the requested
/// pool differ from the specifications of the existing pool, otherwise
/// returns Ok(CreateAction::Identity).
pub fn create_pool_idempotent_or_err(
    pool: &dyn Pool,
    pool_name: &str,
    blockdev_paths: &[&Path],
) -> StratisResult<CreateAction<PoolUuid>> {
    let input_devices: HashSet<PathBuf, RandomState> =
        blockdev_paths.iter().map(|p| p.to_path_buf()).collect();

    let existing_paths: HashSet<PathBuf, _> = pool
        .blockdevs()
        .iter()
        .map(|(_, bd)| bd.devnode())
        .collect();

    if input_devices == existing_paths {
        Ok(CreateAction::Identity)
    } else {
        let in_input = input_devices
            .difference(&existing_paths)
            .map(|path| path.display().to_string())
            .collect::<Vec<_>>();
        let in_pool = existing_paths
            .difference(&input_devices)
            .map(|path| path.display().to_string())
            .collect::<Vec<_>>();
        Err(StratisError::Engine(
            ErrorEnum::Invalid,
            create_pool_generate_error_string!(pool_name, in_input, in_pool),
        ))
    }
}
<commit_msg>Add missing license header<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 std::{
    collections::{hash_map::RandomState, HashSet},
    path::{Path, PathBuf},
};

use crate::{
    engine::{
        engine::Pool,
        types::{CreateAction, PoolUuid},
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

/// Called when the name of a requested pool coincides with the name of an
/// existing pool. Returns an error if the specifications of the requested
/// pool differ from the specifications of the existing pool, otherwise
/// returns Ok(CreateAction::Identity).
pub fn create_pool_idempotent_or_err(
    pool: &dyn Pool,
    pool_name: &str,
    blockdev_paths: &[&Path],
) -> StratisResult<CreateAction<PoolUuid>> {
    let input_devices: HashSet<PathBuf, RandomState> =
        blockdev_paths.iter().map(|p| p.to_path_buf()).collect();

    let existing_paths: HashSet<PathBuf, _> = pool
        .blockdevs()
        .iter()
        .map(|(_, bd)| bd.devnode())
        .collect();

    if input_devices == existing_paths {
        Ok(CreateAction::Identity)
    } else {
        let in_input = input_devices
            .difference(&existing_paths)
            .map(|path| path.display().to_string())
            .collect::<Vec<_>>();
        let in_pool = existing_paths
            .difference(&input_devices)
            .map(|path| path.display().to_string())
            .collect::<Vec<_>>();
        Err(StratisError::Engine(
            ErrorEnum::Invalid,
            create_pool_generate_error_string!(pool_name, in_input, in_pool),
        ))
    }
}
<|endoftext|>


<commit_before>use std::fmt; // Import the `fmt` module.

// Define a structure named `List` containing a `Vec`.
struct List(Vec<i32>);

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Dereference `self` and create a reference to `vec`
        // via destructuring.
        let List(ref vec) = *self;
        let len = vec.len(); // Save the vector length in `len`.

        // Iterate over `vec` in `v` while enumerating the iteration
        // count in `count`.
        for (count, v) in vec.iter().enumerate() {
            // For every element except the last, format `write!`
            // with a comma. Use `try!` to return on errors.
            if count < len - 1 { try!(write!(f, "{}, ", v)) }
        }

        // `write!` the last value without special formatting.
        write!(f, "{}", vec[len-1])
    }
}

fn main() {
    let v = List(vec![1, 2, 3]);
    println!("{}", v);
}
<commit_msg>print_display/testcase_list: fix issue with zero-length vector<commit_after>use std::fmt; // Import the `fmt` module.

// Define a structure named `List` containing a `Vec`.
struct List(Vec<i32>);

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Dereference `self` and create a reference to `vec`
        // via destructuring.
        let List(ref vec) = *self;

        try!(write!(f, "["));

        // Iterate over `vec` in `v` while enumerating the iteration
        // count in `count`.
        for (count, v) in vec.iter().enumerate() {
            // For every element except the first, add a comma
            // before calling `write!`. Use `try!` to return on errors.
            if count != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{}", v));
        }

        // Close the opened bracket and return a fmt::Result value
        write!(f, "]")
    }
}

fn main() {
    let v = List(vec![1, 2, 3]);
    println!("{}", v);
}
<|endoftext|>


<commit_before>// only-x86_64

#![feature(asm, global_asm)]

fn main() {
    unsafe {
        // Outputs must be place expressions

        asm!("{}", in(reg) 1 + 2);
        asm!("{}", out(reg) 1 + 2);
        //~^ ERROR invalid asm output
        asm!("{}", inout(reg) 1 + 2);
        //~^ ERROR invalid asm output

        // Operands must be sized

        let v: [u64; 3] = [0, 1, 2];
        asm!("{}", in(reg) v[..]);
        //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
        asm!("{}", out(reg) v[..]);
        //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
        asm!("{}", inout(reg) v[..]);
        //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time

        // Constants must be... constant

        let x = 0;
        const fn const_foo(x: i32) -> i32 {
            x
        }
        const fn const_bar<T>(x: T) -> T {
            x
        }
        asm!("{}", const x);
        //~^ ERROR attempt to use a non-constant value in a constant
        asm!("{}", const const_foo(0));
        asm!("{}", const const_foo(x));
        //~^ ERROR attempt to use a non-constant value in a constant
        asm!("{}", const const_bar(0));
        asm!("{}", const const_bar(x));
        //~^ ERROR attempt to use a non-constant value in a constant

        // Const operands must be integer and must be constants.

        asm!("{}", const 0);
        asm!("{}", const 0i32);
        asm!("{}", const 0i128);
        asm!("{}", const 0f32);
        //~^ ERROR mismatched types
        asm!("{}", const 0 as *mut u8);
        //~^ ERROR mismatched types
    }
}

// Const operands must be integer or floats, and must be constants.

global_asm!("{}", const 0);
global_asm!("{}", const 0i32);
global_asm!("{}", const 0i128);
global_asm!("{}", const 0f32);
//~^ ERROR mismatched types
global_asm!("{}", const 0 as *mut u8);
//~^ ERROR mismatched types
<commit_msg>Fix comments in tests<commit_after>// only-x86_64

#![feature(asm, global_asm)]

fn main() {
    unsafe {
        // Outputs must be place expressions

        asm!("{}", in(reg) 1 + 2);
        asm!("{}", out(reg) 1 + 2);
        //~^ ERROR invalid asm output
        asm!("{}", inout(reg) 1 + 2);
        //~^ ERROR invalid asm output

        // Operands must be sized

        let v: [u64; 3] = [0, 1, 2];
        asm!("{}", in(reg) v[..]);
        //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
        asm!("{}", out(reg) v[..]);
        //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
        asm!("{}", inout(reg) v[..]);
        //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time

        // Constants must be... constant

        let x = 0;
        const fn const_foo(x: i32) -> i32 {
            x
        }
        const fn const_bar<T>(x: T) -> T {
            x
        }
        asm!("{}", const x);
        //~^ ERROR attempt to use a non-constant value in a constant
        asm!("{}", const const_foo(0));
        asm!("{}", const const_foo(x));
        //~^ ERROR attempt to use a non-constant value in a constant
        asm!("{}", const const_bar(0));
        asm!("{}", const const_bar(x));
        //~^ ERROR attempt to use a non-constant value in a constant

        // Const operands must be integers and must be constants.

        asm!("{}", const 0);
        asm!("{}", const 0i32);
        asm!("{}", const 0i128);
        asm!("{}", const 0f32);
        //~^ ERROR mismatched types
        asm!("{}", const 0 as *mut u8);
        //~^ ERROR mismatched types
    }
}

// Const operands must be integers and must be constants.

global_asm!("{}", const 0);
global_asm!("{}", const 0i32);
global_asm!("{}", const 0i128);
global_asm!("{}", const 0f32);
//~^ ERROR mismatched types
global_asm!("{}", const 0 as *mut u8);
//~^ ERROR mismatched types
<|endoftext|>


<commit_before>use nom::{self, IResult};

use std::str;

// list-wildcards = "%" / "*"
pub fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

// quoted-specials = DQUOTE / "\"
pub fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

// resp-specials = "]"
pub fn resp_specials(c: u8) -> bool {
    c == b']'
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || list_wildcards(c)
        || quoted_specials(c)
        || resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// literal = "{" number "}" CRLF *CHAR8
//            ; Number represents the number of CHAR8s
named!(pub literal<&[u8]>, do_parse!(
    tag!("{") >>
    len: number >>
    tag!("}") >>
    tag!("\r\n") >>
    data: take!(len) >>
    (data)
));

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(nom::character::streaming::digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(nom::character::streaming::digit1, parse_to!(u64)));

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(atom_char),
    str::from_utf8
));

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn text_char(c: u8) -> bool {
    c != b'\r' && c != b'\n'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>Import nom digit1 directly<commit_after>use nom::{self, character::streaming::digit1, IResult};

use std::str;

// list-wildcards = "%" / "*"
pub fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

// quoted-specials = DQUOTE / "\"
pub fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

// resp-specials = "]"
pub fn resp_specials(c: u8) -> bool {
    c == b']'
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || list_wildcards(c)
        || quoted_specials(c)
        || resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// literal = "{" number "}" CRLF *CHAR8
//            ; Number represents the number of CHAR8s
named!(pub literal<&[u8]>, do_parse!(
    tag!("{") >>
    len: number >>
    tag!("}") >>
    tag!("\r\n") >>
    data: take!(len) >>
    (data)
));

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(atom_char),
    str::from_utf8
));

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn text_char(c: u8) -> bool {
    c != b'\r' && c != b'\n'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::Range;

use attribute::Attribute;

/// Represents attributed string.
#[derive(Clone)]
pub struct AttributedString {
    attr_ranges: Vec<AttributeRange>,
    string: String,
}

impl AttributedString {
    /// Creates a new attributed string with the given string.
    pub fn new<T: Into<String>>(string: T) -> Self {
        AttributedString {
            attr_ranges: Vec::new(),
            string: string.into(),
        }
    }

    /// Adds the given attribute to the substring of the specified range in bytes.
    ///
    /// # Panics
    ///
    /// - Panics if `range.end` is greater than `range.start`.
    /// - Panics if `range` does not lie on character boundary of the underlying string.
    pub fn add_attr(&mut self, attr: Attribute, range: Range<usize>) {
        if range.start > range.end {
            panic!("reverse range not allowed");
        }
        if !byte_range_lies_on_char_boundary(&range, &self.string) {
            panic!("range {:?} in `{:?}` does not lie on character boundary", range, &self.string);
        }
        if range.start == range.end {
            return;
        }
        for ar in self.attr_ranges.iter_mut() {
            if ar.attr == attr && is_overlapping_or_adjacent(&ar.range, &range) {
                extend_to_cover(&mut ar.range, &range);
                return;
            }
        }
        self.attr_ranges.push(AttributeRange { attr: attr, range: range });
    }

    /// Returns the length of the underlying string in bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use matsu::AttributedString;
    /// #
    /// let s = AttributedString::new("端末");
    /// assert_eq!(s.len(), 6);
    /// ```
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns a string slice containing the entire underlying string.
    ///
    /// # Examples
    ///
    /// ```
    /// # use matsu::Attribute;
    /// # use matsu::AttributedString;
    /// #
    /// let mut s = AttributedString::new("abc");
    /// s.add_attr(Attribute::Bold, 0..2);
    /// assert_eq!(s.as_plain_str(), "abc");
    /// ```
    pub fn as_plain_str(&self) -> &str {
        self.string.as_ref()
    }

    /// Returns a string formatted by inserting ANSI escape codes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use matsu::Attribute;
    /// # use matsu::AttributedString;
    /// #
    /// let mut s = AttributedString::new("bold and underlined");
    /// s.add_attr(Attribute::Bold, 0..4);
    /// s.add_attr(Attribute::Underline, 9..19);
    /// assert_eq!(s.to_string(), "\x1B[1mbold\x1B[22m and \x1B[4munderlined\x1B[24m");
    /// ```
    ///
    /// In a terminal, the string will be printed as: **bold** and underlined
    pub fn to_string(&self) -> String {
        let mut buf = String::new();
        let mut src_idx = 0usize;
        for (idx, attr, enable) in self.attr_indices().into_iter() {
            if idx > src_idx {
                let substr = &self.string[src_idx..idx];
                buf.push_str(substr);
                src_idx = idx;
            }
            let code = if enable { attr.initiator() } else { attr.terminator() };
            buf.push_str(&code);
        }
        if src_idx < self.string.len() {
            let substr = &self.string[src_idx..];
            buf.push_str(substr);
        }
        buf
    }

    // Returns a vector of `(index, attr, enable)`.
    fn attr_indices(&self) -> Vec<(usize, Attribute, bool)> {
        let mut codes = Vec::new();
        for ar in self.attr_ranges.iter() {
            codes.push((ar.range.start, ar.attr, true));
            codes.push((ar.range.end, ar.attr, false));
        }
        codes.sort_by(|a, b| {
            if a.0 != b.0 { return a.0.cmp(&b.0); }
            a.2.cmp(&b.2) // false < true, i.e., disable < enable
        });
        codes
    }
}

#[derive(Clone)]
struct AttributeRange {
    attr: Attribute,
    range: Range<usize>,
}

fn extend_to_cover(a: &mut Range<usize>, b: &Range<usize>) {
    if a.start > b.start {
        a.start = b.start;
    }
    if a.end < b.end {
        a.end = b.end;
    }
}

fn is_overlapping_or_adjacent(a: &Range<usize>, b: &Range<usize>) -> bool {
    (a.start <= b.end && a.end >= b.start) ||
    (b.start <= a.end && b.end >= a.start)
}

fn byte_range_lies_on_char_boundary(range: &Range<usize>, s: &str) -> bool {
    if range.end > s.len() {
        return false;
    }
    let bytes = unsafe { s.slice_unchecked(range.start, range.end) };
    String::from_utf8(Vec::from(bytes)).is_ok()
}
<commit_msg>Use assert!() instead of if with panic!()<commit_after>use std::ops::Range;

use attribute::Attribute;

/// Represents attributed string.
#[derive(Clone)]
pub struct AttributedString {
    attr_ranges: Vec<AttributeRange>,
    string: String,
}

impl AttributedString {
    /// Creates a new attributed string with the given string.
    pub fn new<T: Into<String>>(string: T) -> Self {
        AttributedString {
            attr_ranges: Vec::new(),
            string: string.into(),
        }
    }

    /// Adds the given attribute to the substring of the specified range in bytes.
    ///
    /// # Panics
    ///
    /// - Panics if `range.end` is greater than `range.start`.
    /// - Panics if `range` does not lie on character boundary of the underlying string.
    pub fn add_attr(&mut self, attr: Attribute, range: Range<usize>) {
        assert!(range.start <= range.end,
            "reverse range not allowed");
        assert!(byte_range_lies_on_char_boundary(&range, &self.string),
            "range {:?} in `{:?}` does not lie on character boundary", range, &self.string);
        if range.start == range.end {
            return;
        }
        for ar in self.attr_ranges.iter_mut() {
            if ar.attr == attr && is_overlapping_or_adjacent(&ar.range, &range) {
                extend_to_cover(&mut ar.range, &range);
                return;
            }
        }
        self.attr_ranges.push(AttributeRange { attr: attr, range: range });
    }

    /// Returns the length of the underlying string in bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use matsu::AttributedString;
    /// #
    /// let s = AttributedString::new("端末");
    /// assert_eq!(s.len(), 6);
    /// ```
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns a string slice containing the entire underlying string.
    ///
    /// # Examples
    ///
    /// ```
    /// # use matsu::Attribute;
    /// # use matsu::AttributedString;
    /// #
    /// let mut s = AttributedString::new("abc");
    /// s.add_attr(Attribute::Bold, 0..2);
    /// assert_eq!(s.as_plain_str(), "abc");
    /// ```
    pub fn as_plain_str(&self) -> &str {
        self.string.as_ref()
    }

    /// Returns a string formatted by inserting ANSI escape codes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use matsu::Attribute;
    /// # use matsu::AttributedString;
    /// #
    /// let mut s = AttributedString::new("bold and underlined");
    /// s.add_attr(Attribute::Bold, 0..4);
    /// s.add_attr(Attribute::Underline, 9..19);
    /// assert_eq!(s.to_string(), "\x1B[1mbold\x1B[22m and \x1B[4munderlined\x1B[24m");
    /// ```
    ///
    /// In a terminal, the string will be printed as: **bold** and underlined
    pub fn to_string(&self) -> String {
        let mut buf = String::new();
        let mut src_idx = 0usize;
        for (idx, attr, enable) in self.attr_indices().into_iter() {
            if idx > src_idx {
                let substr = &self.string[src_idx..idx];
                buf.push_str(substr);
                src_idx = idx;
            }
            let code = if enable { attr.initiator() } else { attr.terminator() };
            buf.push_str(&code);
        }
        if src_idx < self.string.len() {
            let substr = &self.string[src_idx..];
            buf.push_str(substr);
        }
        buf
    }

    // Returns a vector of `(index, attr, enable)`.
    fn attr_indices(&self) -> Vec<(usize, Attribute, bool)> {
        let mut codes = Vec::new();
        for ar in self.attr_ranges.iter() {
            codes.push((ar.range.start, ar.attr, true));
            codes.push((ar.range.end, ar.attr, false));
        }
        codes.sort_by(|a, b| {
            if a.0 != b.0 { return a.0.cmp(&b.0); }
            a.2.cmp(&b.2) // false < true, i.e., disable < enable
        });
        codes
    }
}

#[derive(Clone)]
struct AttributeRange {
    attr: Attribute,
    range: Range<usize>,
}

fn extend_to_cover(a: &mut Range<usize>, b: &Range<usize>) {
    if a.start > b.start {
        a.start = b.start;
    }
    if a.end < b.end {
        a.end = b.end;
    }
}

fn is_overlapping_or_adjacent(a: &Range<usize>, b: &Range<usize>) -> bool {
    (a.start <= b.end && a.end >= b.start) ||
    (b.start <= a.end && b.end >= a.start)
}

fn byte_range_lies_on_char_boundary(range: &Range<usize>, s: &str) -> bool {
    if range.end > s.len() {
        return false;
    }
    let bytes = unsafe { s.slice_unchecked(range.start, range.end) };
    String::from_utf8(Vec::from(bytes)).is_ok()
}
<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::fs;
use std::path::PathBuf;
use std::str::FromStr;

use time;
use walkdir::WalkDir;

use super::Depot;
use super::data_object::{self, DataObject};
use super::data_store::{Cursor, Database, Transaction};
use error::{BldrError, BldrResult};
use package::{self, PackageArchive};

#[derive(Debug)]
/// A struct containing the details of a repair run by `Doctor`.
pub struct Report {
    /// Start time in nanoseconds since epoch.
    pub start: u64,
    /// Finish time in nanoseconds since epoch.
    pub finish: u64,
    /// True if the report contained no errors and false otherwise.
    pub success: bool,
    /// A complete list of operations in the order in which they were performed.
    pub operations: Vec<Operation>,
}

impl Report {
    /// Duration in nanoseconds that the repair took to run.
    pub fn duration(&self) -> u64 {
        (self.finish - self.start)
    }
}

struct ReportBuilder {
    pub operations: Vec<Operation>,
    pub start: u64,
}

impl ReportBuilder {
    pub fn new() -> Self {
        ReportBuilder::default()
    }

    /// Record a successful operation.
    pub fn success(&mut self, operation: OperationType) -> &mut Self {
        self.add(Operation::Success(operation));
        self
    }

    /// Record a failed operation.
    pub fn failure(&mut self, operation: OperationType, reason: Reason) -> &mut Self {
        self.add(Operation::Failure(operation, reason));
        self
    }

    /// Consumes the report builder and returns a completed report.
    pub fn generate(self) -> Report {
        let time = time::precise_time_ns();
        Report {
            start: self.start,
            finish: time,
            success: self.operations.iter().all(Self::check_success),
            operations: self.operations,
        }
    }

    fn add(&mut self, operation: Operation) {
        self.operations.push(operation);
    }

    fn check_success(op: &Operation) -> bool {
        match *op {
            Operation::Success(_) => true,
            Operation::Failure(_, _) => false,
        }
    }
}

impl Default for ReportBuilder {
    fn default() -> Self {
        ReportBuilder {
            operations: vec![],
            start: time::precise_time_ns(),
        }
    }
}

#[derive(Debug)]
pub enum OperationType {
    /// Record of an archive being re-inserted into the datastore. Contains the filepath to the
    /// final location of the archive.
    ArchiveInsert(String),
    /// Record of cleaning up after the doctor has run. Contains the filepath of the trash which
    /// was cleaned.
    CleanupTrash(String),
    /// Record of initializing the depot's datastore filesystem. Contains the filepath of the new
    /// filesystem.
    InitDepotFs(String),
    /// Record of preparing the datastore for re-build. Contains the amount of records dropped from
    /// the database.
    TruncateDatabase(&'static str, usize),
}

#[derive(Debug)]
pub enum Reason {
    BadArchive,
    BadMetadata(BldrError),
    BadPermissions,
    FileExists,
    NotEmpty,
}

#[derive(Debug)]
pub enum Operation {
    Success(OperationType),
    Failure(OperationType, Reason),
}

struct Doctor<'a> {
    report: ReportBuilder,
    depot: &'a Depot,
    packages_path: PathBuf,
}

impl<'a> Doctor<'a> {
    pub fn new(depot: &'a Depot) -> Self {
        let report = ReportBuilder::new();
        let mut packages = depot.packages_path().clone();
        packages.pop();
        packages.push(format!("pkgs.{:?}", report.start));
        Doctor {
            report: report,
            depot: depot,
            packages_path: packages,
        }
    }

    fn run(mut self) -> BldrResult<Report> {
        try!(self.init_fs());
        try!(self.truncate_database(&self.depot.datastore.packages));
        try!(self.rebuild_metadata());
        try!(self.rebuild_indices());
        Ok(self.report.generate())
    }

    fn init_fs(&mut self) -> BldrResult<()> {
        match fs::metadata(&self.depot.path) {
            Ok(meta) => {
                if meta.is_file() {
                    self.report.failure(OperationType::InitDepotFs(self.depot.path.clone()),
                                        Reason::FileExists);
                }
                if meta.permissions().readonly() {
                    self.report.failure(OperationType::InitDepotFs(self.depot.path.clone()),
                                        Reason::BadPermissions);
                }
                try!(fs::create_dir_all(&self.depot.packages_path()));
            }
            Err(_) => try!(fs::create_dir_all(&self.depot.packages_path())),
        }
        try!(fs::rename(&self.depot.packages_path(), &self.packages_path));
        try!(fs::create_dir_all(&self.depot.packages_path()));
        Ok(())
    }

    fn rebuild_indices(&mut self) -> BldrResult<()> {
        let txn = try!(self.depot.datastore.views.pkg_view_idx.txn_rw());
        {
            let tx2 = try!(txn.new_child_rw(&self.depot.datastore.views.view_pkg_idx));
            try!(tx2.clear());
        }
        let mut cursor = try!(txn.cursor_ro());
        loop {
            match cursor.next_nodup() {
                Ok((key, view)) => {
                    match package::PackageIdent::from_str(&key) {
                        Ok(pkident) => {
                            let ident = data_object::PackageIdent::new(pkident);
                            let path = self.depot.archive_path(&ident);
                            match fs::metadata(&path) {
                                Ok(_) => {
                                    let tx2 = try!(txn.new_child_rw(&self.depot
                                                                         .datastore
                                                                         .views
                                                                         .view_pkg_idx));
                                    try!(tx2.put(view.ident(), &ident));
                                    loop {
                                        match cursor.next_dup() {
                                            Ok((_, view)) => {
                                                try!(tx2.put(view.ident(), &ident));
                                            }
                                            Err(_) => break,
                                        }
                                    }
                                }
                                Err(_) => try!(txn.delete(&key, None)),
                            }
                        }
                        Err(_) => try!(txn.delete(&key, None)),
                    }
                }
                Err(_) => break,
            }
        }
        Ok(())
    }

    fn rebuild_metadata(&mut self) -> BldrResult<()> {
        let mut directories = vec![];
        for entry in WalkDir::new(&self.packages_path).follow_links(false) {
            let entry = entry.unwrap();
            if entry.metadata().unwrap().is_dir() {
                directories.push(entry);
                continue;
            }
            let mut archive = PackageArchive::new(PathBuf::from(entry.path()));
            match archive.ident() {
                Ok(ident) => {
                    let path = self.depot.archive_path(&ident);
                    try!(fs::create_dir_all(path.parent().unwrap()));
                    try!(fs::rename(entry.path(), path));

                    let txn = try!(self.depot.datastore.packages.txn_rw());
                    match data_object::Package::from_archive(&mut archive) {
                        Ok(object) => {
                            try!(self.depot.datastore.packages.write(&txn, &object));
                            self.report
                                .success(OperationType::ArchiveInsert(entry.path()
                                                                           .to_string_lossy()
                                                                           .to_string()));
                        }
                        Err(e) => {
                            // We should be moving this back to the garbage directory and recording the
                            // path of it there in this failure
                            self.report
                                .failure(OperationType::ArchiveInsert(entry.path()
                                                                           .to_string_lossy()
                                                                           .to_string()),
                                         Reason::BadMetadata(e));
                        }
                    }
                }
                Err(e) => {
                    debug!("Error reading, archive={:?} error={:?}", &archive, &e);
                    self.report.failure(OperationType::ArchiveInsert(entry.path()
                                                                          .to_string_lossy()
                                                                          .to_string()),
                                        Reason::BadArchive);
                }
            }
        }
        directories.reverse();
        for dir in directories.iter() {
            if let Some(e) = fs::remove_dir(dir.path()).err() {
                debug!("Error deleting: {:?}", &e);
                self.report.failure(OperationType::CleanupTrash(self.packages_path
                                                                    .to_string_lossy()
                                                                    .to_string()),
                                    Reason::NotEmpty);
            }
        }
        Ok(())
    }

    fn truncate_database<D: Database>(&mut self, database: &D) -> BldrResult<()> {
        let count = {
            let txn = try!(database.txn_rw());
            let stats = try!(database.stat(&txn));
            try!(database.clear(&txn));
            stats.entries()
        };
        self.report.success(OperationType::TruncateDatabase(D::name(), count));
        Ok(())
    }
}

/// Runs the repair tool on the given Depot and returns a Report containing the results. A repair
/// tool analyzes all packages found within the Depot's metadata store and re-inserts them into
/// the file system and re-builds all indices.
///
/// Any files found within the metastore which are not valid or readable archives are moved into a
/// gargbage directory for the user to examine.
pub fn repair(depot: &Depot) -> BldrResult<Report> {
    Doctor::new(depot).run()
}
<commit_msg>fix bug where archive was moved before read in rebuilding<commit_after>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::fs;
use std::io;
use std::path::PathBuf;
use std::str::FromStr;

use time;
use walkdir::WalkDir;

use super::Depot;
use super::data_object::{self, DataObject};
use super::data_store::{Cursor, Database, Transaction};
use error::{BldrError, BldrResult};
use package::{self, PackageArchive};

#[derive(Debug)]
/// A struct containing the details of a repair run by `Doctor`.
pub struct Report {
    /// Start time in nanoseconds since epoch.
    pub start: u64,
    /// Finish time in nanoseconds since epoch.
    pub finish: u64,
    /// True if the report contained no errors and false otherwise.
    pub success: bool,
    /// A complete list of operations in the order in which they were performed.
    pub operations: Vec<Operation>,
}

impl Report {
    /// Duration in nanoseconds that the repair took to run.
    pub fn duration(&self) -> u64 {
        (self.finish - self.start)
    }
}

struct ReportBuilder {
    pub operations: Vec<Operation>,
    pub start: u64,
}

impl ReportBuilder {
    pub fn new() -> Self {
        ReportBuilder::default()
    }

    /// Record a successful operation.
    pub fn success(&mut self, operation: OperationType) -> &mut Self {
        self.add(Operation::Success(operation));
        self
    }

    /// Record a failed operation.
    pub fn failure(&mut self, operation: OperationType, reason: Reason) -> &mut Self {
        self.add(Operation::Failure(operation, reason));
        self
    }

    /// Consumes the report builder and returns a completed report.
    pub fn generate(self) -> Report {
        let time = time::precise_time_ns();
        Report {
            start: self.start,
            finish: time,
            success: self.operations.iter().all(Self::check_success),
            operations: self.operations,
        }
    }

    fn add(&mut self, operation: Operation) {
        self.operations.push(operation);
    }

    fn check_success(op: &Operation) -> bool {
        match *op {
            Operation::Success(_) => true,
            Operation::Failure(_, _) => false,
        }
    }
}

impl Default for ReportBuilder {
    fn default() -> Self {
        ReportBuilder {
            operations: vec![],
            start: time::precise_time_ns(),
        }
    }
}

#[derive(Debug)]
pub enum OperationType {
    /// Record of an archive being re-inserted into the datastore. Contains the filepath to the
    /// final location of the archive.
    ArchiveInsert(String),
    /// Record of cleaning up after the doctor has run. Contains the filepath of the trash which
    /// was cleaned.
    CleanupTrash(String),
    /// Record of initializing the depot's datastore filesystem. Contains the filepath of the new
    /// filesystem.
    InitDepotFs(String),
    /// Record of preparing the datastore for re-build. Contains the amount of records dropped from
    /// the database.
    TruncateDatabase(&'static str, usize),
}

#[derive(Debug)]
pub enum Reason {
    BadArchive,
    BadMetadata(BldrError),
    BadPermissions,
    IO(io::Error),
    FileExists,
    NotEmpty,
}

#[derive(Debug)]
pub enum Operation {
    Success(OperationType),
    Failure(OperationType, Reason),
}

struct Doctor<'a> {
    report: ReportBuilder,
    depot: &'a Depot,
    packages_path: PathBuf,
}

impl<'a> Doctor<'a> {
    pub fn new(depot: &'a Depot) -> Self {
        let report = ReportBuilder::new();
        let mut packages = depot.packages_path().clone();
        packages.pop();
        packages.push(format!("pkgs.{:?}", report.start));
        Doctor {
            report: report,
            depot: depot,
            packages_path: packages,
        }
    }

    fn run(mut self) -> BldrResult<Report> {
        try!(self.init_fs());
        try!(self.truncate_database(&self.depot.datastore.packages));
        try!(self.rebuild_metadata());
        try!(self.rebuild_indices());
        Ok(self.report.generate())
    }

    fn init_fs(&mut self) -> BldrResult<()> {
        match fs::metadata(&self.depot.path) {
            Ok(meta) => {
                if meta.is_file() {
                    self.report.failure(OperationType::InitDepotFs(self.depot.path.clone()),
                                        Reason::FileExists);
                }
                if meta.permissions().readonly() {
                    self.report.failure(OperationType::InitDepotFs(self.depot.path.clone()),
                                        Reason::BadPermissions);
                }
                try!(fs::create_dir_all(&self.depot.packages_path()));
            }
            Err(_) => try!(fs::create_dir_all(&self.depot.packages_path())),
        }
        try!(fs::rename(&self.depot.packages_path(), &self.packages_path));
        try!(fs::create_dir_all(&self.depot.packages_path()));
        Ok(())
    }

    fn rebuild_indices(&mut self) -> BldrResult<()> {
        let txn = try!(self.depot.datastore.views.pkg_view_idx.txn_rw());
        {
            let tx2 = try!(txn.new_child_rw(&self.depot.datastore.views.view_pkg_idx));
            try!(tx2.clear());
        }
        let mut cursor = try!(txn.cursor_ro());
        loop {
            match cursor.next_nodup() {
                Ok((key, view)) => {
                    match package::PackageIdent::from_str(&key) {
                        Ok(pkident) => {
                            let ident = data_object::PackageIdent::new(pkident);
                            let path = self.depot.archive_path(&ident);
                            match fs::metadata(&path) {
                                Ok(_) => {
                                    let tx2 = try!(txn.new_child_rw(&self.depot
                                                                         .datastore
                                                                         .views
                                                                         .view_pkg_idx));
                                    try!(tx2.put(view.ident(), &ident));
                                    loop {
                                        match cursor.next_dup() {
                                            Ok((_, view)) => {
                                                try!(tx2.put(view.ident(), &ident));
                                            }
                                            Err(_) => break,
                                        }
                                    }
                                }
                                Err(_) => try!(txn.delete(&key, None)),
                            }
                        }
                        Err(_) => try!(txn.delete(&key, None)),
                    }
                }
                Err(_) => break,
            }
        }
        Ok(())
    }

    fn rebuild_metadata(&mut self) -> BldrResult<()> {
        let mut directories = vec![];
        for entry in WalkDir::new(&self.packages_path).follow_links(false) {
            let entry = entry.unwrap();
            if entry.metadata().unwrap().is_dir() {
                directories.push(entry);
                continue;
            }
            let mut archive = PackageArchive::new(PathBuf::from(entry.path()));
            match archive.ident() {
                Ok(ident) => {
                    let txn = try!(self.depot.datastore.packages.txn_rw());
                    match data_object::Package::from_archive(&mut archive) {
                        Ok(object) => {
                            try!(self.depot.datastore.packages.write(&txn, &object));
                            let path = self.depot.archive_path(&ident);
                            if let Some(e) = fs::create_dir_all(path.parent().unwrap()).err() {
                                self.report
                                    .failure(OperationType::ArchiveInsert(entry.path()
                                                                               .to_string_lossy()
                                                                               .to_string()),
                                             Reason::IO(e));
                                txn.abort();
                                break;
                            }
                            if let Some(e) = fs::rename(entry.path(), &path).err() {
                                self.report
                                    .failure(OperationType::ArchiveInsert(entry.path()
                                                                               .to_string_lossy()
                                                                               .to_string()),
                                             Reason::IO(e));
                                txn.abort();
                                break;
                            }
                            self.report
                                .success(OperationType::ArchiveInsert(path.to_string_lossy()
                                                                          .to_string()));
                        }
                        Err(e) => {
                            // We should be moving this back to the garbage directory and recording the
                            // path of it there in this failure
                            self.report
                                .failure(OperationType::ArchiveInsert(entry.path()
                                                                           .to_string_lossy()
                                                                           .to_string()),
                                         Reason::BadMetadata(e));
                        }
                    }
                }
                Err(e) => {
                    debug!("Error reading, archive={:?} error={:?}", &archive, &e);
                    self.report.failure(OperationType::ArchiveInsert(entry.path()
                                                                          .to_string_lossy()
                                                                          .to_string()),
                                        Reason::BadArchive);
                }
            }
        }
        directories.reverse();
        for dir in directories.iter() {
            if let Some(e) = fs::remove_dir(dir.path()).err() {
                debug!("Error deleting: {:?}", &e);
                self.report.failure(OperationType::CleanupTrash(self.packages_path
                                                                    .to_string_lossy()
                                                                    .to_string()),
                                    Reason::NotEmpty);
            }
        }
        Ok(())
    }

    fn truncate_database<D: Database>(&mut self, database: &D) -> BldrResult<()> {
        let count = {
            let txn = try!(database.txn_rw());
            let stats = try!(database.stat(&txn));
            try!(database.clear(&txn));
            stats.entries()
        };
        self.report.success(OperationType::TruncateDatabase(D::name(), count));
        Ok(())
    }
}

/// Runs the repair tool on the given Depot and returns a Report containing the results. A repair
/// tool analyzes all packages found within the Depot's metadata store and re-inserts them into
/// the file system and re-builds all indices.
///
/// Any files found within the metastore which are not valid or readable archives are moved into a
/// gargbage directory for the user to examine.
pub fn repair(depot: &Depot) -> BldrResult<Report> {
    Doctor::new(depot).run()
}
<|endoftext|>


<commit_before>// Copyright 2013 The CGMath 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.

use std::fmt;
use std::num::{zero, one, cast, sqrt};

use angle::{Angle, Rad, acos, cos, sin, sin_cos};
use approx::ApproxEq;
use array::{Array, build};
use matrix::{Mat3, ToMat3};
use vector::{Vec3, Vector, EuclideanVector};

/// A quaternion in scalar/vector form
#[deriving(Clone, Eq)]
pub struct Quat<S> { s: S, v: Vec3<S> }

array!(impl<S> Quat<S> -> [S, ..4] _4)

pub trait ToQuat<S: Float> {
    fn to_quat(&self) -> Quat<S>;
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Construct a new quaternion from one scalar component and three
    /// imaginary components
    #[inline]
    pub fn new(w: S, xi: S, yj: S, zk: S) -> Quat<S> {
        Quat::from_sv(w, Vec3::new(xi, yj, zk))
    }

    /// Construct a new quaternion from a scalar and a vector
    #[inline]
    pub fn from_sv(s: S, v: Vec3<S>) -> Quat<S> {
        Quat { s: s, v: v }
    }

    /// Create a matrix from a rotation around the `x` axis (pitch).
    #[inline]
    pub fn from_angle_x(theta: Rad<S>) -> Quat<S> {
        Quat::new(cos(theta.mul_s(cast(0.5).unwrap())), sin(theta), zero(), zero())
    }

    /// Create a matrix from a rotation around the `y` axis (yaw).
    #[inline]
    pub fn from_angle_y(theta: Rad<S>) -> Quat<S> {
        Quat::new(cos(theta.mul_s(cast(0.5).unwrap())), zero(), sin(theta), zero())
    }

    /// Create a matrix from a rotation around the `z` axis (roll).
    #[inline]
    pub fn from_angle_z(theta: Rad<S>) -> Quat<S> {
        Quat::new(cos(theta.mul_s(cast(0.5).unwrap())), zero(), zero(), sin(theta))
    }

    /// Create a quaternion from a set of euler angles.
    ///
    /// # Parameters
    ///
    /// - `x`: the angular rotation around the `x` axis (pitch).
    /// - `y`: the angular rotation around the `y` axis (yaw).
    /// - `z`: the angular rotation around the `z` axis (roll).
    pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Quat<S> {
        // http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Conversion
        let (sx2, cx2) = sin_cos(x.mul_s(cast(0.5).unwrap()));
        let (sy2, cy2) = sin_cos(y.mul_s(cast(0.5).unwrap()));
        let (sz2, cz2) = sin_cos(z.mul_s(cast(0.5).unwrap()));

        Quat::new(cz2 * cx2 * cy2 + sz2 * sx2 * sy2,
                  sz2 * cx2 * cy2 - cz2 * sx2 * sy2,
                  cz2 * sx2 * cy2 + sz2 * cx2 * sy2,
                  cz2 * cx2 * sy2 - sz2 * sx2 * cy2)
    }

    /// Create a quaternion from a rotation around an arbitrary axis
    #[inline]
    pub fn from_axis_angle(axis: &Vec3<S>, angle: Rad<S>) -> Quat<S> {
        let half = angle.mul_s(cast(0.5).unwrap());
        Quat::from_sv(cos(half.clone()),
                      axis.mul_s(sin(half)))
    }

    /// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
    #[inline]
    pub fn zero() -> Quat<S> {
        Quat::new(zero(), zero(), zero(), zero())
    }

    /// The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i`
    #[inline]
    pub fn identity() -> Quat<S> {
        Quat::from_sv(one::<S>(), Vec3::zero())
    }

    /// The result of multiplying the quaternion a scalar
    #[inline]
    pub fn mul_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s * value, self.v.mul_s(value))
    }

    /// The result of dividing the quaternion a scalar
    #[inline]
    pub fn div_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s / value, self.v.div_s(value))
    }

    /// The result of multiplying the quaternion by a vector
    #[inline]
    pub fn mul_v(&self, vec: &Vec3<S>) -> Vec3<S>  {
        let tmp = self.v.cross(vec).add_v(&vec.mul_s(self.s.clone()));
        self.v.cross(&tmp).mul_s(cast(2).unwrap()).add_v(vec)
    }

    /// The sum of this quaternion and `other`
    #[inline]
    pub fn add_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The difference between this quaternion and `other`
    #[inline]
    pub fn sub_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The the result of multipliplying the quaternion by `other`
    pub fn mul_q(&self, other: &Quat<S>) -> Quat<S> {
        Quat::new(self.s * other.s - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z,
                  self.s * other.v.x + self.v.x * other.s + self.v.y * other.v.z - self.v.z * other.v.y,
                  self.s * other.v.y + self.v.y * other.s + self.v.z * other.v.x - self.v.x * other.v.z,
                  self.s * other.v.z + self.v.z * other.s + self.v.x * other.v.y - self.v.y * other.v.x)
    }

    #[inline]
    pub fn mul_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.mul(&s))
    }

    #[inline]
    pub fn div_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.div(&s))
    }

    #[inline]
    pub fn add_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.add(other.i(i)));
    }

    #[inline]
    pub fn sub_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.sub(other.i(i)));
    }

    #[inline]
    pub fn mul_self_q(&mut self, other: &Quat<S>) {
        *self = self.mul_q(other);
    }

    /// The dot product of the quaternion and `other`
    #[inline]
    pub fn dot(&self, other: &Quat<S>) -> S {
        self.s * other.s + self.v.dot(&other.v)
    }

    /// The conjugate of the quaternion
    #[inline]
    pub fn conjugate(&self) -> Quat<S> {
        Quat::from_sv(self.s.clone(), -self.v.clone())
    }

    /// The squared magnitude of the quaternion. This is useful for
    /// magnitude comparisons where the exact magnitude does not need to be
    /// calculated.
    #[inline]
    pub fn magnitude2(&self) -> S {
        self.s * self.s + self.v.length2()
    }

    /// The magnitude of the quaternion
    ///
    /// # Performance notes
    ///
    /// For instances where the exact magnitude of the quaternion does not need
    /// to be known, for example for quaternion-quaternion magnitude comparisons,
    /// it is advisable to use the `magnitude2` method instead.
    #[inline]
    pub fn magnitude(&self) -> S {
        sqrt(self.magnitude2())
    }

    /// The normalized quaternion
    #[inline]
    pub fn normalize(&self) -> Quat<S> {
        self.mul_s(one::<S>() / self.magnitude())
    }

    /// Normalised linear interpolation
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    pub fn nlerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        self.mul_s(one::<S>() - amount).add_q(&other.mul_s(amount)).normalize()
    }
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Spherical Linear Intoperlation
    ///
    /// Perform a spherical linear interpolation between the quaternion and
    /// `other`. Both quaternions should be normalized first.
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    ///
    /// # Performance notes
    ///
    /// The `acos` operation used in `slerp` is an expensive operation, so unless
    /// your quarternions a far away from each other it's generally more advisable
    /// to use `nlerp` when you know your rotations are going to be small.
    ///
    /// - [Understanding Slerp, Then Not Using It]
    ///   (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)
    /// - [Arcsynthesis OpenGL tutorial]
    ///   (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
    pub fn slerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        use std::num::cast;

        let dot = self.dot(other);
        let dot_threshold = cast(0.9995).unwrap();

        // if quaternions are close together use `nlerp`
        if dot > dot_threshold {
            self.nlerp(other, amount)
        } else {
            // stay within the domain of acos()
            let robust_dot = dot.clamp(&-one::<S>(), &one::<S>());

            let theta: Rad<S> = acos(robust_dot.clone());

            let scale1 = sin(theta.mul_s(one::<S>() - amount));
            let scale2 = sin(theta.mul_s(amount));

            self.mul_s(scale1)
                .add_q(&other.mul_s(scale2))
                .mul_s(sin(theta).recip())
        }
    }
}

impl<S: Float + ApproxEq<S>>
ToMat3<S> for Quat<S> {
    /// Convert the quaternion to a 3 x 3 rotation matrix
    fn to_mat3(&self) -> Mat3<S> {
        let x2 = self.v.x + self.v.x;
        let y2 = self.v.y + self.v.y;
        let z2 = self.v.z + self.v.z;

        let xx2 = x2 * self.v.x;
        let xy2 = x2 * self.v.y;
        let xz2 = x2 * self.v.z;

        let yy2 = y2 * self.v.y;
        let yz2 = y2 * self.v.z;
        let zz2 = z2 * self.v.z;

        let sy2 = y2 * self.s;
        let sz2 = z2 * self.s;
        let sx2 = x2 * self.s;

        Mat3::new(one::<S>() - yy2 - zz2, xy2 + sz2, xz2 - sy2,
                  xy2 - sz2, one::<S>() - xx2 - zz2, yz2 + sx2,
                  xz2 + sy2, yz2 - sx2, one::<S>() - xx2 - yy2)
    }
}

impl<S: Float + ApproxEq<S>>
Neg<Quat<S>> for Quat<S> {
    #[inline]
    fn neg(&self) -> Quat<S> {
        Quat::from_sv(-self.s, -self.v)
    }
}

impl<S: fmt::Default> ToStr for Quat<S> {
    fn to_str(&self) -> ~str {
        format!("{} + {}i + {}j + {}k", self.s, self.v.x, self.v.y, self.v.z)
    }
}
<commit_msg>Fix quat::Quat::from_angle_{x|y|z}<commit_after>// Copyright 2013 The CGMath 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.

use std::fmt;
use std::num::{zero, one, cast, sqrt};

use angle::{Angle, Rad, acos, cos, sin, sin_cos};
use approx::ApproxEq;
use array::{Array, build};
use matrix::{Mat3, ToMat3};
use vector::{Vec3, Vector, EuclideanVector};

/// A quaternion in scalar/vector form
#[deriving(Clone, Eq)]
pub struct Quat<S> { s: S, v: Vec3<S> }

array!(impl<S> Quat<S> -> [S, ..4] _4)

pub trait ToQuat<S: Float> {
    fn to_quat(&self) -> Quat<S>;
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Construct a new quaternion from one scalar component and three
    /// imaginary components
    #[inline]
    pub fn new(w: S, xi: S, yj: S, zk: S) -> Quat<S> {
        Quat::from_sv(w, Vec3::new(xi, yj, zk))
    }

    /// Construct a new quaternion from a scalar and a vector
    #[inline]
    pub fn from_sv(s: S, v: Vec3<S>) -> Quat<S> {
        Quat { s: s, v: v }
    }

    /// Create a matrix from a rotation around the `x` axis (pitch).
    #[inline]
    pub fn from_angle_x(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, s, zero(), zero())
    }

    /// Create a matrix from a rotation around the `y` axis (yaw).
    #[inline]
    pub fn from_angle_y(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, zero(), s, zero())
    }

    /// Create a matrix from a rotation around the `z` axis (roll).
    #[inline]
    pub fn from_angle_z(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, zero(), zero(), s)
    }

    /// Create a quaternion from a set of euler angles.
    ///
    /// # Parameters
    ///
    /// - `x`: the angular rotation around the `x` axis (pitch).
    /// - `y`: the angular rotation around the `y` axis (yaw).
    /// - `z`: the angular rotation around the `z` axis (roll).
    pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Quat<S> {
        // http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Conversion
        let (sx2, cx2) = sin_cos(x.mul_s(cast(0.5).unwrap()));
        let (sy2, cy2) = sin_cos(y.mul_s(cast(0.5).unwrap()));
        let (sz2, cz2) = sin_cos(z.mul_s(cast(0.5).unwrap()));

        Quat::new(cz2 * cx2 * cy2 + sz2 * sx2 * sy2,
                  sz2 * cx2 * cy2 - cz2 * sx2 * sy2,
                  cz2 * sx2 * cy2 + sz2 * cx2 * sy2,
                  cz2 * cx2 * sy2 - sz2 * sx2 * cy2)
    }

    /// Create a quaternion from a rotation around an arbitrary axis
    #[inline]
    pub fn from_axis_angle(axis: &Vec3<S>, angle: Rad<S>) -> Quat<S> {
        let half = angle.mul_s(cast(0.5).unwrap());
        Quat::from_sv(cos(half.clone()),
                      axis.mul_s(sin(half)))
    }

    /// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
    #[inline]
    pub fn zero() -> Quat<S> {
        Quat::new(zero(), zero(), zero(), zero())
    }

    /// The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i`
    #[inline]
    pub fn identity() -> Quat<S> {
        Quat::from_sv(one::<S>(), Vec3::zero())
    }

    /// The result of multiplying the quaternion a scalar
    #[inline]
    pub fn mul_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s * value, self.v.mul_s(value))
    }

    /// The result of dividing the quaternion a scalar
    #[inline]
    pub fn div_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s / value, self.v.div_s(value))
    }

    /// The result of multiplying the quaternion by a vector
    #[inline]
    pub fn mul_v(&self, vec: &Vec3<S>) -> Vec3<S>  {
        let tmp = self.v.cross(vec).add_v(&vec.mul_s(self.s.clone()));
        self.v.cross(&tmp).mul_s(cast(2).unwrap()).add_v(vec)
    }

    /// The sum of this quaternion and `other`
    #[inline]
    pub fn add_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The difference between this quaternion and `other`
    #[inline]
    pub fn sub_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The the result of multipliplying the quaternion by `other`
    pub fn mul_q(&self, other: &Quat<S>) -> Quat<S> {
        Quat::new(self.s * other.s - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z,
                  self.s * other.v.x + self.v.x * other.s + self.v.y * other.v.z - self.v.z * other.v.y,
                  self.s * other.v.y + self.v.y * other.s + self.v.z * other.v.x - self.v.x * other.v.z,
                  self.s * other.v.z + self.v.z * other.s + self.v.x * other.v.y - self.v.y * other.v.x)
    }

    #[inline]
    pub fn mul_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.mul(&s))
    }

    #[inline]
    pub fn div_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.div(&s))
    }

    #[inline]
    pub fn add_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.add(other.i(i)));
    }

    #[inline]
    pub fn sub_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.sub(other.i(i)));
    }

    #[inline]
    pub fn mul_self_q(&mut self, other: &Quat<S>) {
        *self = self.mul_q(other);
    }

    /// The dot product of the quaternion and `other`
    #[inline]
    pub fn dot(&self, other: &Quat<S>) -> S {
        self.s * other.s + self.v.dot(&other.v)
    }

    /// The conjugate of the quaternion
    #[inline]
    pub fn conjugate(&self) -> Quat<S> {
        Quat::from_sv(self.s.clone(), -self.v.clone())
    }

    /// The squared magnitude of the quaternion. This is useful for
    /// magnitude comparisons where the exact magnitude does not need to be
    /// calculated.
    #[inline]
    pub fn magnitude2(&self) -> S {
        self.s * self.s + self.v.length2()
    }

    /// The magnitude of the quaternion
    ///
    /// # Performance notes
    ///
    /// For instances where the exact magnitude of the quaternion does not need
    /// to be known, for example for quaternion-quaternion magnitude comparisons,
    /// it is advisable to use the `magnitude2` method instead.
    #[inline]
    pub fn magnitude(&self) -> S {
        sqrt(self.magnitude2())
    }

    /// The normalized quaternion
    #[inline]
    pub fn normalize(&self) -> Quat<S> {
        self.mul_s(one::<S>() / self.magnitude())
    }

    /// Normalised linear interpolation
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    pub fn nlerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        self.mul_s(one::<S>() - amount).add_q(&other.mul_s(amount)).normalize()
    }
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Spherical Linear Intoperlation
    ///
    /// Perform a spherical linear interpolation between the quaternion and
    /// `other`. Both quaternions should be normalized first.
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    ///
    /// # Performance notes
    ///
    /// The `acos` operation used in `slerp` is an expensive operation, so unless
    /// your quarternions a far away from each other it's generally more advisable
    /// to use `nlerp` when you know your rotations are going to be small.
    ///
    /// - [Understanding Slerp, Then Not Using It]
    ///   (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)
    /// - [Arcsynthesis OpenGL tutorial]
    ///   (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
    pub fn slerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        use std::num::cast;

        let dot = self.dot(other);
        let dot_threshold = cast(0.9995).unwrap();

        // if quaternions are close together use `nlerp`
        if dot > dot_threshold {
            self.nlerp(other, amount)
        } else {
            // stay within the domain of acos()
            let robust_dot = dot.clamp(&-one::<S>(), &one::<S>());

            let theta: Rad<S> = acos(robust_dot.clone());

            let scale1 = sin(theta.mul_s(one::<S>() - amount));
            let scale2 = sin(theta.mul_s(amount));

            self.mul_s(scale1)
                .add_q(&other.mul_s(scale2))
                .mul_s(sin(theta).recip())
        }
    }
}

impl<S: Float + ApproxEq<S>>
ToMat3<S> for Quat<S> {
    /// Convert the quaternion to a 3 x 3 rotation matrix
    fn to_mat3(&self) -> Mat3<S> {
        let x2 = self.v.x + self.v.x;
        let y2 = self.v.y + self.v.y;
        let z2 = self.v.z + self.v.z;

        let xx2 = x2 * self.v.x;
        let xy2 = x2 * self.v.y;
        let xz2 = x2 * self.v.z;

        let yy2 = y2 * self.v.y;
        let yz2 = y2 * self.v.z;
        let zz2 = z2 * self.v.z;

        let sy2 = y2 * self.s;
        let sz2 = z2 * self.s;
        let sx2 = x2 * self.s;

        Mat3::new(one::<S>() - yy2 - zz2, xy2 + sz2, xz2 - sy2,
                  xy2 - sz2, one::<S>() - xx2 - zz2, yz2 + sx2,
                  xz2 + sy2, yz2 - sx2, one::<S>() - xx2 - yy2)
    }
}

impl<S: Float + ApproxEq<S>>
Neg<Quat<S>> for Quat<S> {
    #[inline]
    fn neg(&self) -> Quat<S> {
        Quat::from_sv(-self.s, -self.v)
    }
}

impl<S: fmt::Default> ToStr for Quat<S> {
    fn to_str(&self) -> ~str {
        format!("{} + {}i + {}j + {}k", self.s, self.v.x, self.v.y, self.v.z)
    }
}
<|endoftext|>


<commit_before>extern crate rgmk;
extern crate env_logger;

fn main() {
    env_logger::init().unwrap();
    let path = std::env::args().skip(1).next().expect("Expected file name as argument");
    let gamedata = rgmk::GameData::from_file(&path).unwrap();
    for chunk in &gamedata.code.code_chunks {
        let name = &gamedata.strings.strings[chunk.name_index][..];
        println!("Code chunk == \"{}\" ==\n{:?}", name, chunk.raw_code);
    }
}
<commit_msg>Improve byte dump output in dump_code<commit_after>extern crate rgmk;
extern crate env_logger;

fn main() {
    env_logger::init().unwrap();
    let path = std::env::args().skip(1).next().expect("Expected file name as argument");
    let gamedata = rgmk::GameData::from_file(&path).unwrap();
    for chunk in &gamedata.code.code_chunks {
        let name = &gamedata.strings.strings[chunk.name_index][..];
        println!("Code chunk == \"{}\" ==", name);
        for b in &chunk.raw_code {
            print!("{:02X} ", b);
        }
        print!("\n");
    }
}
<|endoftext|>