<commit_before>use common::*;
use env_logger;
use std::fmt;
use std::io::{Read, Write};
use std::num::Wrapping;

mod events;
mod memory;
mod modes;
mod opcodes;
mod registers;

use self::events::*;
use self::memory::*;
use self::modes::*;
use self::opcodes::*;
use self::registers::*;

include!("tests.rs");

pub struct VM<R: Read, W: Write> {
    input: R,
    output: W,

    registers: Registers,
    memory: Memory,
    terminated: bool,
}

impl<R: Read, W: Write> VM<R, W> {
    pub fn new(input: R, output: W, executable: Data) -> Self {
        let memory = Memory::from_executable(executable);

        VM {
            input: input,
            output: output,
            registers: [0; REGISTERS as usize],
            memory: memory,
            terminated: false,
        }
    }

    pub fn run(&mut self) {
        self.set_register(PC, CODE_OFFSET as Word);

        let stack_end = self.memory.stack_end;
        self.set_register(SP, stack_end);

        let event_queue_end = self.memory.event_queue_end;
        self.set_register(EP, event_queue_end);
        self.set_register(EE, event_queue_end);

        let mut args = vec![];
        while !self.terminated {
            let pc = self.get_register(PC);
            if !self.memory.is_in_code(pc) && self.event_queue().is_empty() {
                self.terminate();
            } else {
                self.fetch()
                    .decode(&mut args)
                    .execute(&args)
                    .process_events();
                args.clear();
            }
        }

        self.output.flush().unwrap();
    }

    pub fn code(&self) -> DataSlice {
        self.memory.code()
    }

    pub fn data(&self) -> DataSlice {
        self.memory.data()
    }

    pub fn stack(&self) -> DataSlice {
        let sp = self.get_register(SP);
        self.memory.stack(sp)
    }

    pub fn event_queue(&self) -> DataSlice {
        let ep = self.get_register(EP);
        let ee = self.get_register(EE);
        self.memory.event_queue(ep, ee)
    }

    fn terminate(&mut self) {
        debug!("terminate {:?}", self);
        self.terminated = true;
    }

    fn fetch(&mut self) -> &mut Self {
        debug!("fetch {:?}", self);

        let opcode = self.next_code_byte() as Word;
        self.set_register(IR, opcode);
        self
    }

    fn decode(&mut self, args: &mut Data) -> &mut Self {
        debug!("decode {:?}", self);

        let opcode = self.get_register(IR) as u8;
        match opcode {
            PUSH => args.push(self.next_code_byte()),
            POP | NOP => (),
            EMIT => {
                let event = self.next_code_byte();
                let argument = if self.stack().is_empty() {
                    0x00
                } else {
                    self.stack_top()
                };
                args.push(event);
                args.push(argument);
            }
            ADD | SUB | MUL | DIV | MOD => {
                args.push(self.stack_pop());
                args.push(self.stack_pop());
            }
            INC | DEC => args.push(self.stack_pop()),
            _ => unimplemented!(),
        }

        self
    }

    fn execute(&mut self, args: DataSlice) -> &mut Self {
        debug!("execute {:?}", self);

        let opcode = self.get_register(IR) as u8;
        match opcode {
            NOP => (),
            PUSH => {
                if self.get_register(SP) <= self.memory.stack_begin {
                    self.process_event(SEGFAULT, 0x00);
                } else {
                    self.stack_push(args[0]);
                }
            }
            POP => {
                if self.stack().is_empty() {
                    self.process_event(SEGFAULT, 0x00);
                } else {
                    let _ = self.stack_pop();
                }
            }
            ADD => {
                let value = Wrapping(args[0]) + Wrapping(args[1]);
                self.stack_push(value.0);
            }
            SUB => {
                let value = Wrapping(args[0]) - Wrapping(args[1]);
                self.stack_push(value.0);
            }
            MUL => {
                let value = Wrapping(args[0]) * Wrapping(args[1]);
                self.stack_push(value.0);
            }
            DIV => {
                if args[1] == 0 {
                    self.process_event(UNKNOWN_ERROR, 0x00);
                } else {
                    let value = Wrapping(args[0]) / Wrapping(args[1]);
                    self.stack_push(value.0);
                }
            }
            MOD => {
                if args[1] == 0 {
                    self.process_event(UNKNOWN_ERROR, 0x00);
                } else {
                    let value = Wrapping(args[0]) % Wrapping(args[1]);
                    self.stack_push(value.0);
                }
            }
            INC => {
                let value = Wrapping(args[0]) + Wrapping(1);
                self.stack_push(value.0);
            }
            DEC => {
                let value = Wrapping(args[0]) - Wrapping(1);
                self.stack_push(value.0);
            }
            EMIT => {
                let event = args[0];
                let argument = args[1];
                if events::is_critical(event) {
                    self.process_event(event, argument);
                } else {
                    self.event_queue_push(event, argument);
                }
            }
            _ => unimplemented!(),
        }

        self
    }

    fn process_event(&mut self, event: u8, argument: u8) {
        debug!("process_event event={} argument={}",
               to_hex!(event),
               to_hex!(argument));

        let handler = self.memory.get_event_handler(event);
        if handler == 0 {
            debug!("handler is NOT set");
            match event {
                INPUT => {
                    let mut buffer = [0; 1];
                    let _ = self.input.read(&mut buffer).unwrap();
                    self.stack_push(buffer[0]);
                }
                OUTPUT => {
                    self.output.write(&[argument]).unwrap();
                }
                SEGFAULT => {
                    self.output.write(b"Segfault").unwrap();
                }
                UNKNOWN_ERROR => {
                    self.output.write(b"Unknown Error").unwrap();
                }
                _ => debug!("no default handler"),
            }

            if events::is_critical(event) {
                self.terminate();
            }
        } else {
            debug!("handler is set");
            let pc = self.get_register(PC);
            self.stack_push_word(pc);
            self.stack_push(argument);
            self.set_register(PC, handler);
        }
    }

    fn process_events(&mut self) {
        let nothing_to_process = self.terminated || self.event_queue().is_empty();
        if !nothing_to_process {
            let (event, argument) = self.event_queue_pop();
            self.process_event(event, argument);
        }
    }

    fn event_queue_push(&mut self, event: u8, argument: u8) {
        self.decrement_register(EP);
        let ep = self.get_register(EP);
        self.memory.put(ep, argument);

        self.decrement_register(EP);
        let ep = self.get_register(EP);
        self.memory.put(ep, event);
    }

    fn event_queue_pop(&mut self) -> (u8, u8) {
        let ee = self.get_register(EE);
        let ep = self.get_register(EP);
        assert_lt!(ep, ee);

        self.decrement_register(EE);
        let ee = self.get_register(EE);
        let argument = self.memory.get(ee);

        self.decrement_register(EE);
        let ee = self.get_register(EE);
        let event = self.memory.get(ee);

        if ep == ee {
            let event_queue_end = self.memory.event_queue_end;
            self.set_register(EP, event_queue_end);
            self.set_register(EE, event_queue_end);
        }

        (event, argument)
    }

    fn next_code_byte(&mut self) -> u8 {
        let code_begin = self.get_register(PC);
        let value = self.memory.get(code_begin);
        self.increment_register(PC);
        value
    }

    fn get_register(&self, id: u8) -> Word {
        self.registers[id as usize]
    }

    fn set_register(&mut self, id: u8, value: Word) {
        debug!("set r{:x} = {}", id, to_hex!(value));
        self.registers[id as usize] = value;
    }

    fn increment_register(&mut self, id: u8) {
        self.registers[id as usize] += 1;
    }

    fn decrement_register(&mut self, id: u8) {
        self.registers[id as usize] -= 1;
    }

    fn stack_top(&self) -> u8 {
        let sp = self.get_register(SP);
        self.memory.get(sp)
    }

    fn stack_pop(&mut self) -> u8 {
        debug!("stack_pop {} from [{}]",
               to_hex!(self.stack_top()),
               data_to_hex(self.stack()));
        let value = self.stack_top();
        self.increment_register(SP);
        value
    }

    fn stack_push(&mut self, value: u8) {
        debug!("stack_push {} to [{}]",
               to_hex!(value),
               data_to_hex(self.stack()));
        self.decrement_register(SP);
        let sp = self.get_register(SP);
        self.memory.put(sp, value);
    }

    fn stack_push_word(&mut self, value: Word) {
        debug!("stack_push_word to [{}]", data_to_hex(self.stack()));
        unimplemented!()
    }
}

impl<R: Read, W: Write> fmt::Debug for VM<R, W> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "PC={} SP={} IR={} EP={} stack=[{}] code=[{}]",
               to_hex!(self.get_register(PC)),
               to_hex!(self.get_register(SP)),
               to_hex!(self.get_register(IR)),
               to_hex!(self.get_register(EP)),
               data_to_hex(self.stack()),
               data_to_hex(self.code()))
    }
}
<commit_msg>refactoring<commit_after>use common::*;
use env_logger;
use std::fmt;
use std::io::{Read, Write};
use std::num::Wrapping;

mod events;
mod memory;
mod modes;
mod opcodes;
mod registers;

use self::events::*;
use self::memory::*;
use self::modes::*;
use self::opcodes::*;
use self::registers::*;

include!("tests.rs");

pub struct VM<R: Read, W: Write> {
    input: R,
    output: W,

    registers: Registers,
    memory: Memory,
    terminated: bool,
}

impl<R: Read, W: Write> VM<R, W> {
    pub fn new(input: R, output: W, executable: Data) -> Self {
        let memory = Memory::from_executable(executable);

        VM {
            input: input,
            output: output,
            registers: [0; REGISTERS as usize],
            memory: memory,
            terminated: false,
        }
    }

    pub fn run(&mut self) {
        self.set_register(PC, CODE_OFFSET as Word);

        let stack_end = self.memory.stack_end;
        self.set_register(SP, stack_end);

        let event_queue_end = self.memory.event_queue_end;
        self.set_register(EP, event_queue_end);
        self.set_register(EE, event_queue_end);

        let mut args = vec![];
        while !self.terminated {
            let pc = self.get_register(PC);
            if !self.memory.is_in_code(pc) && self.event_queue().is_empty() {
                self.terminate();
            } else {
                self.fetch()
                    .decode(&mut args)
                    .execute(&args)
                    .process_events();
                args.clear();
            }
        }

        self.output.flush().unwrap();
    }

    pub fn code(&self) -> DataSlice {
        self.memory.code()
    }

    pub fn data(&self) -> DataSlice {
        self.memory.data()
    }

    pub fn stack(&self) -> DataSlice {
        let sp = self.get_register(SP);
        self.memory.stack(sp)
    }

    pub fn event_queue(&self) -> DataSlice {
        let ep = self.get_register(EP);
        let ee = self.get_register(EE);
        self.memory.event_queue(ep, ee)
    }

    fn terminate(&mut self) {
        debug!("terminate {:?}", self);
        self.terminated = true;
    }

    fn fetch(&mut self) -> &mut Self {
        debug!("fetch {:?}", self);

        let opcode = self.next_code_byte() as Word;
        self.set_register(IR, opcode);
        self
    }

    fn decode(&mut self, args: &mut Data) -> &mut Self {
        debug!("decode {:?}", self);

        let opcode = self.get_register(IR) as u8;
        match opcode {
            ADD | SUB | MUL | DIV | MOD => {
                args.push(self.stack_pop());
                args.push(self.stack_pop());
            }
            INC | DEC => args.push(self.stack_pop()),
            PUSH => args.push(self.next_code_byte()),
            POP | NOP => (),
            EMIT => {
                let event = self.next_code_byte();
                let argument = if self.stack().is_empty() {
                    0x00
                } else {
                    self.stack_top()
                };
                args.push(event);
                args.push(argument);
            }
            _ => unimplemented!(),
        }

        self
    }

    fn execute(&mut self, args: DataSlice) -> &mut Self {
        debug!("execute {:?}", self);

        let opcode = self.get_register(IR) as u8;
        match opcode {
            NOP => (),
            ADD => {
                let value = Wrapping(args[0]) + Wrapping(args[1]);
                self.stack_push(value.0);
            }
            SUB => {
                let value = Wrapping(args[0]) - Wrapping(args[1]);
                self.stack_push(value.0);
            }
            MUL => {
                let value = Wrapping(args[0]) * Wrapping(args[1]);
                self.stack_push(value.0);
            }
            DIV => {
                if args[1] == 0 {
                    self.process_event(UNKNOWN_ERROR, 0x00);
                } else {
                    let value = Wrapping(args[0]) / Wrapping(args[1]);
                    self.stack_push(value.0);
                }
            }
            MOD => {
                if args[1] == 0 {
                    self.process_event(UNKNOWN_ERROR, 0x00);
                } else {
                    let value = Wrapping(args[0]) % Wrapping(args[1]);
                    self.stack_push(value.0);
                }
            }
            INC => {
                let value = Wrapping(args[0]) + Wrapping(1);
                self.stack_push(value.0);
            }
            DEC => {
                let value = Wrapping(args[0]) - Wrapping(1);
                self.stack_push(value.0);
            }
            PUSH => {
                if self.get_register(SP) <= self.memory.stack_begin {
                    self.process_event(SEGFAULT, 0x00);
                } else {
                    self.stack_push(args[0]);
                }
            }
            POP => {
                if self.stack().is_empty() {
                    self.process_event(SEGFAULT, 0x00);
                } else {
                    let _ = self.stack_pop();
                }
            }
            EMIT => {
                let event = args[0];
                let argument = args[1];
                if events::is_critical(event) {
                    self.process_event(event, argument);
                } else {
                    self.event_queue_push(event, argument);
                }
            }
            _ => unimplemented!(),
        }

        self
    }

    fn process_event(&mut self, event: u8, argument: u8) {
        debug!("process_event event={} argument={}",
               to_hex!(event),
               to_hex!(argument));

        let handler = self.memory.get_event_handler(event);
        if handler == 0 {
            debug!("handler is NOT set");
            match event {
                INPUT => {
                    let mut buffer = [0; 1];
                    let _ = self.input.read(&mut buffer).unwrap();
                    self.stack_push(buffer[0]);
                }
                OUTPUT => {
                    self.output.write(&[argument]).unwrap();
                }
                SEGFAULT => {
                    self.output.write(b"Segfault").unwrap();
                }
                UNKNOWN_ERROR => {
                    self.output.write(b"Unknown Error").unwrap();
                }
                _ => debug!("no default handler"),
            }

            if events::is_critical(event) {
                self.terminate();
            }
        } else {
            debug!("handler is set");
            let pc = self.get_register(PC);
            self.stack_push_word(pc);
            self.stack_push(argument);
            self.set_register(PC, handler);
        }
    }

    fn process_events(&mut self) {
        let nothing_to_process = self.terminated || self.event_queue().is_empty();
        if !nothing_to_process {
            let (event, argument) = self.event_queue_pop();
            self.process_event(event, argument);
        }
    }

    fn event_queue_push(&mut self, event: u8, argument: u8) {
        self.decrement_register(EP);
        let ep = self.get_register(EP);
        self.memory.put(ep, argument);

        self.decrement_register(EP);
        let ep = self.get_register(EP);
        self.memory.put(ep, event);
    }

    fn event_queue_pop(&mut self) -> (u8, u8) {
        let ee = self.get_register(EE);
        let ep = self.get_register(EP);
        assert_lt!(ep, ee);

        self.decrement_register(EE);
        let ee = self.get_register(EE);
        let argument = self.memory.get(ee);

        self.decrement_register(EE);
        let ee = self.get_register(EE);
        let event = self.memory.get(ee);

        if ep == ee {
            let event_queue_end = self.memory.event_queue_end;
            self.set_register(EP, event_queue_end);
            self.set_register(EE, event_queue_end);
        }

        (event, argument)
    }

    fn next_code_byte(&mut self) -> u8 {
        let code_begin = self.get_register(PC);
        let value = self.memory.get(code_begin);
        self.increment_register(PC);
        value
    }

    fn get_register(&self, id: u8) -> Word {
        self.registers[id as usize]
    }

    fn set_register(&mut self, id: u8, value: Word) {
        debug!("set r{:x} = {}", id, to_hex!(value));
        self.registers[id as usize] = value;
    }

    fn increment_register(&mut self, id: u8) {
        self.registers[id as usize] += 1;
    }

    fn decrement_register(&mut self, id: u8) {
        self.registers[id as usize] -= 1;
    }

    fn stack_top(&self) -> u8 {
        let sp = self.get_register(SP);
        self.memory.get(sp)
    }

    fn stack_pop(&mut self) -> u8 {
        debug!("stack_pop {} from [{}]",
               to_hex!(self.stack_top()),
               data_to_hex(self.stack()));
        let value = self.stack_top();
        self.increment_register(SP);
        value
    }

    fn stack_push(&mut self, value: u8) {
        debug!("stack_push {} to [{}]",
               to_hex!(value),
               data_to_hex(self.stack()));
        self.decrement_register(SP);
        let sp = self.get_register(SP);
        self.memory.put(sp, value);
    }

    fn stack_push_word(&mut self, value: Word) {
        debug!("stack_push_word to [{}]", data_to_hex(self.stack()));
        unimplemented!()
    }
}

impl<R: Read, W: Write> fmt::Debug for VM<R, W> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "PC={} SP={} IR={} EP={} stack=[{}] code=[{}]",
               to_hex!(self.get_register(PC)),
               to_hex!(self.get_register(SP)),
               to_hex!(self.get_register(IR)),
               to_hex!(self.get_register(EP)),
               data_to_hex(self.stack()),
               data_to_hex(self.code()))
    }
}
<|endoftext|>


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

extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;
extern crate synstructure;

#[cfg(not(test))]
#[proc_macro_derive(JSTraceable)]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    expand_string(&input.to_string()).parse().unwrap()
}

fn expand_string(input: &str) -> String {
    let mut type_ = syn::parse_macro_input(input).unwrap();

    let style = synstructure::BindStyle::Ref.into();
    let match_body = synstructure::each_field(&mut type_, &style, |binding| {
        Some(quote! { #binding.trace(tracer); })
    });

    let name = &type_.ident;
    let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl();
    let mut where_clause = where_clause.clone();
    for param in &type_.generics.ty_params {
        where_clause.predicates.push(syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
            bound_lifetimes: Vec::new(),
            bounded_ty: syn::Ty::Path(None, param.ident.clone().into()),
            bounds: vec![syn::TyParamBound::Trait(
                syn::PolyTraitRef {
                    bound_lifetimes: Vec::new(),
                    trait_ref: syn::parse_path("::dom::bindings::trace::JSTraceable").unwrap(),
                },
                syn::TraitBoundModifier::None
            )],
        }))
    }

    let tokens = quote! {
        #[allow(unsafe_code)]
        unsafe impl #impl_generics ::dom::bindings::trace::JSTraceable for #name #ty_generics #where_clause {
            #[inline]
            #[allow(unused_variables, unused_imports)]
            unsafe fn trace(&self, tracer: *mut ::js::jsapi::JSTracer) {
                use ::dom::bindings::trace::JSTraceable;
                match *self {
                    #match_body
                }
            }
        }
    };

    tokens.to_string()
}
<commit_msg>Remove a useless cfg attribute<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/. */

extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;
extern crate synstructure;

#[proc_macro_derive(JSTraceable)]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    expand_string(&input.to_string()).parse().unwrap()
}

fn expand_string(input: &str) -> String {
    let mut type_ = syn::parse_macro_input(input).unwrap();

    let style = synstructure::BindStyle::Ref.into();
    let match_body = synstructure::each_field(&mut type_, &style, |binding| {
        Some(quote! { #binding.trace(tracer); })
    });

    let name = &type_.ident;
    let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl();
    let mut where_clause = where_clause.clone();
    for param in &type_.generics.ty_params {
        where_clause.predicates.push(syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
            bound_lifetimes: Vec::new(),
            bounded_ty: syn::Ty::Path(None, param.ident.clone().into()),
            bounds: vec![syn::TyParamBound::Trait(
                syn::PolyTraitRef {
                    bound_lifetimes: Vec::new(),
                    trait_ref: syn::parse_path("::dom::bindings::trace::JSTraceable").unwrap(),
                },
                syn::TraitBoundModifier::None
            )],
        }))
    }

    let tokens = quote! {
        #[allow(unsafe_code)]
        unsafe impl #impl_generics ::dom::bindings::trace::JSTraceable for #name #ty_generics #where_clause {
            #[inline]
            #[allow(unused_variables, unused_imports)]
            unsafe fn trace(&self, tracer: *mut ::js::jsapi::JSTracer) {
                use ::dom::bindings::trace::JSTraceable;
                match *self {
                    #match_body
                }
            }
        }
    };

    tokens.to_string()
}
<|endoftext|>


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

use smallvec::SmallVec;
use webgpu::wgpu::{
    hub::IdentityManager,
    id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
    Backend,
};

#[derive(Debug)]
pub struct IdentityHub {
    adapters: IdentityManager,
    devices: IdentityManager,
    buffers: IdentityManager,
    bind_group_layouts: IdentityManager,
    pipeline_layouts: IdentityManager,
    backend: Backend,
}

impl IdentityHub {
    fn new(backend: Backend) -> Self {
        IdentityHub {
            adapters: IdentityManager::default(),
            devices: IdentityManager::default(),
            buffers: IdentityManager::default(),
            bind_group_layouts: IdentityManager::default(),
            pipeline_layouts: IdentityManager::default(),
            backend,
        }
    }

    fn create_adapter_id(&mut self) -> AdapterId {
        self.adapters.alloc(self.backend)
    }

    fn create_device_id(&mut self) -> DeviceId {
        self.devices.alloc(self.backend)
    }

    fn create_buffer_id(&mut self) -> BufferId {
        self.buffers.alloc(self.backend)
    }

    fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
        self.bind_group_layouts.alloc(self.backend)
    }

    fn create_pipeline_layout_id(&mut self) -> PipelineLayoutId {
        self.pipeline_layouts.alloc(self.backend)
    }
}

#[derive(Debug)]
pub struct Identities {
    surface: IdentityManager,
    #[cfg(any(target_os = "linux", target_os = "windows"))]
    vk_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx12_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx11_hub: IdentityHub,
    #[cfg(any(target_os = "ios", target_os = "macos"))]
    metal_hub: IdentityHub,
    dummy_hub: IdentityHub,
}

impl Identities {
    pub fn new() -> Self {
        Identities {
            surface: IdentityManager::default(),
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            vk_hub: IdentityHub::new(Backend::Vulkan),
            #[cfg(target_os = "windows")]
            dx12_hub: IdentityHub::new(Backend::Dx12),
            #[cfg(target_os = "windows")]
            dx11_hub: IdentityHub::new(Backend::Dx11),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            metal_hub: IdentityHub::new(Backend::Metal),
            dummy_hub: IdentityHub::new(Backend::Empty),
        }
    }

    fn hubs(&mut self) -> Vec<&mut IdentityHub> {
        vec![
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            &mut self.vk_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx12_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx11_hub,
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            &mut self.metal_hub,
            &mut self.dummy_hub,
        ]
    }

    pub fn create_device_id(&mut self, backend: Backend) -> DeviceId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_device_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_device_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_device_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_device_id(),
            _ => self.dummy_hub.create_device_id(),
        }
    }

    pub fn create_adapter_ids(&mut self) -> SmallVec<[AdapterId; 4]> {
        let mut ids = SmallVec::new();
        for hub in self.hubs() {
            ids.push(hub.create_adapter_id())
        }
        ids
    }

    pub fn create_buffer_id(&mut self, backend: Backend) -> BufferId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_buffer_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_buffer_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_buffer_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_buffer_id(),
            _ => self.dummy_hub.create_buffer_id(),
        }
    }

    pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_bind_group_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_bind_group_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_bind_group_layout_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_bind_group_layout_id(),
            _ => self.dummy_hub.create_bind_group_layout_id(),
        }
    }

    pub fn create_pipeline_layout_id(&mut self, backend: Backend) -> PipelineLayoutId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_pipeline_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_pipeline_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_pipeline_layout_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_pipeline_layout_id(),
            _ => self.dummy_hub.create_pipeline_layout_id(),
        }
    }
}
<commit_msg>Remove code duplication from IdentityHub<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 https://mozilla.org/MPL/2.0/. */

use smallvec::SmallVec;
use webgpu::wgpu::{
    hub::IdentityManager,
    id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
    Backend,
};

#[derive(Debug)]
pub struct IdentityHub {
    adapters: IdentityManager,
    devices: IdentityManager,
    buffers: IdentityManager,
    bind_group_layouts: IdentityManager,
    pipeline_layouts: IdentityManager,
    backend: Backend,
}

impl IdentityHub {
    fn new(backend: Backend) -> Self {
        IdentityHub {
            adapters: IdentityManager::default(),
            devices: IdentityManager::default(),
            buffers: IdentityManager::default(),
            bind_group_layouts: IdentityManager::default(),
            pipeline_layouts: IdentityManager::default(),
            backend,
        }
    }

    fn create_adapter_id(&mut self) -> AdapterId {
        self.adapters.alloc(self.backend)
    }

    fn create_device_id(&mut self) -> DeviceId {
        self.devices.alloc(self.backend)
    }

    fn create_buffer_id(&mut self) -> BufferId {
        self.buffers.alloc(self.backend)
    }

    fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
        self.bind_group_layouts.alloc(self.backend)
    }

    fn create_pipeline_layout_id(&mut self) -> PipelineLayoutId {
        self.pipeline_layouts.alloc(self.backend)
    }
}

#[derive(Debug)]
pub struct Identities {
    surface: IdentityManager,
    #[cfg(any(target_os = "linux", target_os = "windows"))]
    vk_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx12_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx11_hub: IdentityHub,
    #[cfg(any(target_os = "ios", target_os = "macos"))]
    metal_hub: IdentityHub,
    dummy_hub: IdentityHub,
}

impl Identities {
    pub fn new() -> Self {
        Identities {
            surface: IdentityManager::default(),
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            vk_hub: IdentityHub::new(Backend::Vulkan),
            #[cfg(target_os = "windows")]
            dx12_hub: IdentityHub::new(Backend::Dx12),
            #[cfg(target_os = "windows")]
            dx11_hub: IdentityHub::new(Backend::Dx11),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            metal_hub: IdentityHub::new(Backend::Metal),
            dummy_hub: IdentityHub::new(Backend::Empty),
        }
    }

    fn select(&mut self, backend: Backend) -> &mut IdentityHub {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => &mut self.vk_hub,
            #[cfg(target_os = "windows")]
            Backend::Dx12 => &mut self.dx12_hub,
            #[cfg(target_os = "windows")]
            Backend::Dx11 => &mut self.dx11_hub,
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => &mut self.metal_hub,
            _ => &mut self.dummy_hub,
        }
    }

    fn hubs(&mut self) -> Vec<&mut IdentityHub> {
        vec![
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            &mut self.vk_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx12_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx11_hub,
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            &mut self.metal_hub,
            &mut self.dummy_hub,
        ]
    }

    pub fn create_device_id(&mut self, backend: Backend) -> DeviceId {
        self.select(backend).create_device_id()
    }

    pub fn create_adapter_ids(&mut self) -> SmallVec<[AdapterId; 4]> {
        let mut ids = SmallVec::new();
        for hub in self.hubs() {
            ids.push(hub.create_adapter_id())
        }
        ids
    }

    pub fn create_buffer_id(&mut self, backend: Backend) -> BufferId {
        self.select(backend).create_buffer_id()
    }

    pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
        self.select(backend).create_bind_group_layout_id()
    }

    pub fn create_pipeline_layout_id(&mut self, backend: Backend) -> PipelineLayoutId {
        self.select(backend).create_pipeline_layout_id()
    }
}
<|endoftext|>


<commit_before>fn _length_length(length: usize) -> u8 {
    let mut i = length;
    let mut num_bytes = 1;
    while i > 255 {
        num_bytes += 1;
        i >>= 8;
    }
    num_bytes
}
fn _insert_at_position(vec: &mut Vec<u8>, pos: usize, data: &[u8]) {
    for _ in 0..data.len() {
        vec.push(0);
    }
    let src_range = pos..vec.len() - data.len();
    vec.copy_within(src_range, pos + data.len());
    vec[pos..pos + data.len()].copy_from_slice(data);
}

enum Storage<'a> {
    Owned(Vec<u8>),
    Borrowed(&'a mut Vec<u8>),
}

impl Storage<'_> {
    #[inline]
    fn as_mut_ref(&mut self) -> &mut Vec<u8> {
        match self {
            Storage::Owned(ref mut v) => v,
            Storage::Borrowed(v) => v,
        }
    }
}

pub struct Writer<'a> {
    data: Storage<'a>,
}

impl Writer<'_> {
    #[inline]
    fn new() -> Writer<'static> {
        Writer {
            data: Storage::Owned(vec![]),
        }
    }

    #[inline]
    pub(crate) fn new_with_storage<'a>(data: &'a mut Vec<u8>) -> Writer<'a> {
        Writer {
            data: Storage::Borrowed(data),
        }
    }

    #[inline]
    pub fn write_element<'a, T>(&mut self, val: T)
    where
        T: crate::types::SimpleAsn1Element<'a, WriteType = T>,
    {
        self.write_element_with_type::<T>(val);
    }

    #[inline]
    pub fn write_element_with_type<'a, T>(&mut self, val: T::WriteType)
    where
        T: crate::types::SimpleAsn1Element<'a>,
    {
        self.data.as_mut_ref().push(T::TAG);
        // Push a 0-byte placeholder for the length. Needing only a single byte
        // for the element is probably the most common case.
        self.data.as_mut_ref().push(0);
        let start_len = self.data.as_mut_ref().len();
        T::write_data(self.data.as_mut_ref(), val);
        let added_len = self.data.as_mut_ref().len() - start_len;
        if added_len >= 128 {
            let n = _length_length(added_len);
            self.data.as_mut_ref()[start_len - 1] = 0x80 | n;
            let mut length_buf = [0u8; 8];
            for (pos, i) in (1..n + 1).rev().enumerate() {
                length_buf[pos] = (added_len >> ((i - 1) * 8)) as u8;
            }
            _insert_at_position(self.data.as_mut_ref(), start_len, &length_buf[..n as usize]);
        } else {
            self.data.as_mut_ref()[start_len - 1] = added_len as u8;
        }
    }

    #[inline]
    fn build(self) -> Vec<u8> {
        match self.data {
            Storage::Owned(v) => v,
            Storage::Borrowed(_) => panic!("Can't call build with borrowed storage"),
        }
    }
}

#[inline]
pub fn write<F: Fn(&mut Writer)>(f: F) -> Vec<u8> {
    let mut w = Writer::new();
    f(&mut w);
    w.build()
}

#[cfg(test)]
mod tests {
    use chrono::{TimeZone, Utc};

    use super::{_insert_at_position, write, Writer};
    use crate::types::SimpleAsn1Element;
    use crate::{
        BitString, Explicit, Implicit, ObjectIdentifier, PrintableString, Sequence, UtcTime,
    };

    fn assert_writes<'a, T>(data: &[(T::WriteType, &[u8])])
    where
        T: SimpleAsn1Element<'a>,
        T::WriteType: Clone,
    {
        for (val, expected) in data {
            let result = write(|w| {
                w.write_element_with_type::<T>(val.clone());
            });
            assert_eq!(&result, expected);
        }
    }

    #[test]
    fn test_insert_at_position() {
        let mut v = vec![1, 2, 3, 4];
        _insert_at_position(&mut v, 2, &[5, 6]);
        assert_eq!(&v, &[1, 2, 5, 6, 3, 4]);
    }

    #[test]
    fn test_write_element() {
        assert_eq!(write(|w| w.write_element(())), b"\x05\x00");
    }

    #[test]
    fn test_write_null() {
        assert_writes::<()>(&[((), b"\x05\x00")]);
    }

    #[test]
    fn test_write_bool() {
        assert_writes::<bool>(&[(false, b"\x01\x01\x00"), (true, b"\x01\x01\xff")]);
    }

    #[test]
    fn test_write_octet_string() {
        assert_writes::<&[u8]>(&[
            (b"", b"\x04\x00"),
            (b"\x01\x02\x03", b"\x04\x03\x01\x02\x03"),
            (b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", b"\x04\x81\x81aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
        ])
    }

    #[test]
    fn test_write_printable_string() {
        assert_writes::<PrintableString>(&[
            (
                PrintableString::new("Test User 1").unwrap(),
                b"\x13\x0bTest User 1",
            ),
            (
                PrintableString::new("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").unwrap(),
                b"\x13\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            ),
        ]);
    }

    #[test]
    fn test_write_i64() {
        assert_writes::<i64>(&[
            (0, b"\x02\x01\x00"),
            (127, b"\x02\x01\x7f"),
            (128, b"\x02\x02\x00\x80"),
            (255, b"\x02\x02\x00\xff"),
            (256, b"\x02\x02\x01\x00"),
            (-1, b"\x02\x01\xff"),
            (-128, b"\x02\x01\x80"),
            (-129, b"\x02\x02\xff\x7f"),
        ]);
    }

    #[test]
    fn test_write_i8() {
        assert_writes::<i8>(&[
            (0, b"\x02\x01\x00"),
            (127, b"\x02\x01\x7f"),
            (-1, b"\x02\x01\xff"),
            (-128, b"\x02\x01\x80"),
        ]);
    }

    #[test]
    fn test_write_object_identifier() {
        assert_writes::<ObjectIdentifier>(&[
            (
                ObjectIdentifier::from_string("1.2.840.113549").unwrap(),
                b"\x06\x06\x2a\x86\x48\x86\xf7\x0d",
            ),
            (
                ObjectIdentifier::from_string("1.2.3.4").unwrap(),
                b"\x06\x03\x2a\x03\x04",
            ),
            (
                ObjectIdentifier::from_string("1.2.840.133549.1.1.5").unwrap(),
                b"\x06\x09\x2a\x86\x48\x88\x93\x2d\x01\x01\x05",
            ),
            (
                ObjectIdentifier::from_string("2.100.3").unwrap(),
                b"\x06\x03\x81\x34\x03",
            ),
        ]);
    }

    #[test]
    fn test_write_bit_string() {
        assert_writes::<BitString>(&[
            (BitString::new(b"", 0).unwrap(), b"\x03\x01\x00"),
            (BitString::new(b"\x80", 7).unwrap(), b"\x03\x02\x07\x80"),
            (
                BitString::new(b"\x81\xf0", 4).unwrap(),
                b"\x03\x03\x04\x81\xf0",
            ),
        ]);
    }

    #[test]
    fn test_write_utctime() {
        assert_writes::<UtcTime>(&[
            (
                Utc.ymd(1991, 5, 6).and_hms(23, 45, 40),
                b"\x17\x0d910506234540Z",
            ),
            (Utc.timestamp(0, 0), b"\x17\x0d700101000000Z"),
            (Utc.timestamp(1258325776, 0), b"\x17\x0d091115225616Z"),
        ]);
    }

    #[test]
    fn test_write_sequence() {
        assert_eq!(
            write(|w| {
                w.write_element_with_type::<Sequence>(&|w: &mut Writer| w.write_element(()))
            }),
            b"\x30\x02\x05\x00"
        );
        assert_eq!(
            write(|w| {
                w.write_element_with_type::<Sequence>(&|w: &mut Writer| w.write_element(true))
            }),
            b"\x30\x03\x01\x01\xff"
        );
    }

    #[test]
    fn test_write_implicit() {
        assert_writes::<Implicit<bool, 2>>(&[(true, b"\x82\x01\xff"), (false, b"\x82\x01\x00")]);
    }

    #[test]
    fn test_write_explicit() {
        assert_writes::<Explicit<bool, 2>>(&[
            (true, b"\xa2\x03\x01\x01\xff"),
            (false, b"\xa2\x03\x01\x01\x00"),
        ]);
    }
}
<commit_msg>Satisfy clippy<commit_after>fn _length_length(length: usize) -> u8 {
    let mut i = length;
    let mut num_bytes = 1;
    while i > 255 {
        num_bytes += 1;
        i >>= 8;
    }
    num_bytes
}
fn _insert_at_position(vec: &mut Vec<u8>, pos: usize, data: &[u8]) {
    for _ in 0..data.len() {
        vec.push(0);
    }
    let src_range = pos..vec.len() - data.len();
    vec.copy_within(src_range, pos + data.len());
    vec[pos..pos + data.len()].copy_from_slice(data);
}

enum Storage<'a> {
    Owned(Vec<u8>),
    Borrowed(&'a mut Vec<u8>),
}

impl Storage<'_> {
    #[inline]
    fn as_mut_ref(&mut self) -> &mut Vec<u8> {
        match self {
            Storage::Owned(ref mut v) => v,
            Storage::Borrowed(v) => v,
        }
    }
}

pub struct Writer<'a> {
    data: Storage<'a>,
}

impl Writer<'_> {
    #[inline]
    fn new() -> Writer<'static> {
        Writer {
            data: Storage::Owned(vec![]),
        }
    }

    #[inline]
    pub(crate) fn new_with_storage(data: &mut Vec<u8>) -> Writer {
        Writer {
            data: Storage::Borrowed(data),
        }
    }

    #[inline]
    pub fn write_element<'a, T>(&mut self, val: T)
    where
        T: crate::types::SimpleAsn1Element<'a, WriteType = T>,
    {
        self.write_element_with_type::<T>(val);
    }

    #[inline]
    pub fn write_element_with_type<'a, T>(&mut self, val: T::WriteType)
    where
        T: crate::types::SimpleAsn1Element<'a>,
    {
        self.data.as_mut_ref().push(T::TAG);
        // Push a 0-byte placeholder for the length. Needing only a single byte
        // for the element is probably the most common case.
        self.data.as_mut_ref().push(0);
        let start_len = self.data.as_mut_ref().len();
        T::write_data(self.data.as_mut_ref(), val);
        let added_len = self.data.as_mut_ref().len() - start_len;
        if added_len >= 128 {
            let n = _length_length(added_len);
            self.data.as_mut_ref()[start_len - 1] = 0x80 | n;
            let mut length_buf = [0u8; 8];
            for (pos, i) in (1..n + 1).rev().enumerate() {
                length_buf[pos] = (added_len >> ((i - 1) * 8)) as u8;
            }
            _insert_at_position(self.data.as_mut_ref(), start_len, &length_buf[..n as usize]);
        } else {
            self.data.as_mut_ref()[start_len - 1] = added_len as u8;
        }
    }

    #[inline]
    fn build(self) -> Vec<u8> {
        match self.data {
            Storage::Owned(v) => v,
            Storage::Borrowed(_) => panic!("Can't call build with borrowed storage"),
        }
    }
}

#[inline]
pub fn write<F: Fn(&mut Writer)>(f: F) -> Vec<u8> {
    let mut w = Writer::new();
    f(&mut w);
    w.build()
}

#[cfg(test)]
mod tests {
    use chrono::{TimeZone, Utc};

    use super::{_insert_at_position, write, Writer};
    use crate::types::SimpleAsn1Element;
    use crate::{
        BitString, Explicit, Implicit, ObjectIdentifier, PrintableString, Sequence, UtcTime,
    };

    fn assert_writes<'a, T>(data: &[(T::WriteType, &[u8])])
    where
        T: SimpleAsn1Element<'a>,
        T::WriteType: Clone,
    {
        for (val, expected) in data {
            let result = write(|w| {
                w.write_element_with_type::<T>(val.clone());
            });
            assert_eq!(&result, expected);
        }
    }

    #[test]
    fn test_insert_at_position() {
        let mut v = vec![1, 2, 3, 4];
        _insert_at_position(&mut v, 2, &[5, 6]);
        assert_eq!(&v, &[1, 2, 5, 6, 3, 4]);
    }

    #[test]
    fn test_write_element() {
        assert_eq!(write(|w| w.write_element(())), b"\x05\x00");
    }

    #[test]
    fn test_write_null() {
        assert_writes::<()>(&[((), b"\x05\x00")]);
    }

    #[test]
    fn test_write_bool() {
        assert_writes::<bool>(&[(false, b"\x01\x01\x00"), (true, b"\x01\x01\xff")]);
    }

    #[test]
    fn test_write_octet_string() {
        assert_writes::<&[u8]>(&[
            (b"", b"\x04\x00"),
            (b"\x01\x02\x03", b"\x04\x03\x01\x02\x03"),
            (b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", b"\x04\x81\x81aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
        ])
    }

    #[test]
    fn test_write_printable_string() {
        assert_writes::<PrintableString>(&[
            (
                PrintableString::new("Test User 1").unwrap(),
                b"\x13\x0bTest User 1",
            ),
            (
                PrintableString::new("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").unwrap(),
                b"\x13\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            ),
        ]);
    }

    #[test]
    fn test_write_i64() {
        assert_writes::<i64>(&[
            (0, b"\x02\x01\x00"),
            (127, b"\x02\x01\x7f"),
            (128, b"\x02\x02\x00\x80"),
            (255, b"\x02\x02\x00\xff"),
            (256, b"\x02\x02\x01\x00"),
            (-1, b"\x02\x01\xff"),
            (-128, b"\x02\x01\x80"),
            (-129, b"\x02\x02\xff\x7f"),
        ]);
    }

    #[test]
    fn test_write_i8() {
        assert_writes::<i8>(&[
            (0, b"\x02\x01\x00"),
            (127, b"\x02\x01\x7f"),
            (-1, b"\x02\x01\xff"),
            (-128, b"\x02\x01\x80"),
        ]);
    }

    #[test]
    fn test_write_object_identifier() {
        assert_writes::<ObjectIdentifier>(&[
            (
                ObjectIdentifier::from_string("1.2.840.113549").unwrap(),
                b"\x06\x06\x2a\x86\x48\x86\xf7\x0d",
            ),
            (
                ObjectIdentifier::from_string("1.2.3.4").unwrap(),
                b"\x06\x03\x2a\x03\x04",
            ),
            (
                ObjectIdentifier::from_string("1.2.840.133549.1.1.5").unwrap(),
                b"\x06\x09\x2a\x86\x48\x88\x93\x2d\x01\x01\x05",
            ),
            (
                ObjectIdentifier::from_string("2.100.3").unwrap(),
                b"\x06\x03\x81\x34\x03",
            ),
        ]);
    }

    #[test]
    fn test_write_bit_string() {
        assert_writes::<BitString>(&[
            (BitString::new(b"", 0).unwrap(), b"\x03\x01\x00"),
            (BitString::new(b"\x80", 7).unwrap(), b"\x03\x02\x07\x80"),
            (
                BitString::new(b"\x81\xf0", 4).unwrap(),
                b"\x03\x03\x04\x81\xf0",
            ),
        ]);
    }

    #[test]
    fn test_write_utctime() {
        assert_writes::<UtcTime>(&[
            (
                Utc.ymd(1991, 5, 6).and_hms(23, 45, 40),
                b"\x17\x0d910506234540Z",
            ),
            (Utc.timestamp(0, 0), b"\x17\x0d700101000000Z"),
            (Utc.timestamp(1258325776, 0), b"\x17\x0d091115225616Z"),
        ]);
    }

    #[test]
    fn test_write_sequence() {
        assert_eq!(
            write(|w| {
                w.write_element_with_type::<Sequence>(&|w: &mut Writer| w.write_element(()))
            }),
            b"\x30\x02\x05\x00"
        );
        assert_eq!(
            write(|w| {
                w.write_element_with_type::<Sequence>(&|w: &mut Writer| w.write_element(true))
            }),
            b"\x30\x03\x01\x01\xff"
        );
    }

    #[test]
    fn test_write_implicit() {
        assert_writes::<Implicit<bool, 2>>(&[(true, b"\x82\x01\xff"), (false, b"\x82\x01\x00")]);
    }

    #[test]
    fn test_write_explicit() {
        assert_writes::<Explicit<bool, 2>>(&[
            (true, b"\xa2\x03\x01\x01\xff"),
            (false, b"\xa2\x03\x01\x01\x00"),
        ]);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::io::{Read, Write, Result};
use timeinfo::TimeInfo;

// use data::SideData;

#[derive(Debug, Clone, PartialEq)]
pub struct Packet {
    pub data : Vec<u8>,
    pub pos : Option<usize>,
    pub stream_index : isize,
    pub t: TimeInfo,

    // side_data : SideData;

    pub is_key: bool,
    pub is_corrupted: bool,
}

impl Packet {
    pub fn with_capacity(capacity: usize) -> Self {
        Packet {
            data : Vec::with_capacity(capacity),
            t: TimeInfo::default(),
            pos : None,
            stream_index : -1,
            is_key: false,
            is_corrupted: false,
        }
    }

    pub fn new() -> Self {
        Self::with_capacity(0)
    }
}

pub trait ReadPacket: Read {
    fn get_packet(&mut self, len: usize) -> Result<Packet> {
        let mut pkt = Packet::with_capacity(len);
        unsafe {
            pkt.data.set_len(len);
            try!(self.read(pkt.data.as_mut_slice()));
        }
        Ok(pkt)
    }
}

pub trait WritePacket: Write {
    fn put_packet(&mut self, pkt: Packet) -> Result<()> {
        self.write_all(pkt.data.as_slice())
    }
}

impl<R: Read + ?Sized> ReadPacket for R {}
impl<W: Write + ?Sized> WritePacket for W {}

#[cfg(test)]
mod test {
    use std::io::Cursor;
    use super::*;

    #[test]
    fn read_packet() {
        let mut buf = Cursor::new(vec![0; 1024]);

        match buf.get_packet(1024) {
            Ok(pkt) => assert!(pkt.data[0] == 0),
            _ => assert!(false)
        }
    }

    #[test]
    fn write_packet() {
        let size = 1024;
        let mut buf = Cursor::new(Vec::with_capacity(size));

        let mut pkt = Packet::with_capacity(size);

        for i in 0..size {
            pkt.data.push(i as u8);
        }

        buf.put_packet(pkt).unwrap();

        let vec = buf.into_inner();

        for i in 0..size {
            println!("{}", vec[i]);
            assert!(vec[i] == i as u8);
        }
    }
}
<commit_msg>data: Add ArcPacket<commit_after>#![allow(dead_code)]

use std::io::{Read, Write, Result};
use timeinfo::TimeInfo;

// use data::SideData;

#[derive(Debug, Clone, PartialEq)]
pub struct Packet {
    pub data : Vec<u8>,
    pub pos : Option<usize>,
    pub stream_index : isize,
    pub t: TimeInfo,

    // side_data : SideData;

    pub is_key: bool,
    pub is_corrupted: bool,
}

impl Packet {
    pub fn with_capacity(capacity: usize) -> Self {
        Packet {
            data : Vec::with_capacity(capacity),
            t: TimeInfo::default(),
            pos : None,
            stream_index : -1,
            is_key: false,
            is_corrupted: false,
        }
    }

    pub fn new() -> Self {
        Self::with_capacity(0)
    }
}

pub trait ReadPacket: Read {
    fn get_packet(&mut self, len: usize) -> Result<Packet> {
        let mut pkt = Packet::with_capacity(len);
        unsafe {
            pkt.data.set_len(len);
            try!(self.read(pkt.data.as_mut_slice()));
        }
        Ok(pkt)
    }
}

pub trait WritePacket: Write {
    fn put_packet(&mut self, pkt: Packet) -> Result<()> {
        self.write_all(pkt.data.as_slice())
    }
}

impl<R: Read + ?Sized> ReadPacket for R {}
impl<W: Write + ?Sized> WritePacket for W {}

use std::sync::Arc;

pub type ArcPacket = Arc<Packet>;

#[cfg(test)]
mod test {
    use std::io::Cursor;
    use super::*;

    #[test]
    fn read_packet() {
        let mut buf = Cursor::new(vec![0; 1024]);

        match buf.get_packet(1024) {
            Ok(pkt) => assert!(pkt.data[0] == 0),
            _ => assert!(false)
        }
    }

    #[test]
    fn write_packet() {
        let size = 1024;
        let mut buf = Cursor::new(Vec::with_capacity(size));

        let mut pkt = Packet::with_capacity(size);

        for i in 0..size {
            pkt.data.push(i as u8);
        }

        buf.put_packet(pkt).unwrap();

        let vec = buf.into_inner();

        for i in 0..size {
            println!("{}", vec[i]);
            assert!(vec[i] == i as u8);
        }
    }
}
<|endoftext|>


<commit_before>//! Constants
//!
//! The constant pool defined here allows cranelift to avoid emitting the same constant multiple
//! times. As constants are inserted in the pool, a handle is returned; the handle is a cranelift
//! Entity. Inserting the same data multiple times will always return the same handle. Future work
//! could include: ensuring alignment of constants within the pool, bucketing constants by size.

use crate::ir::Constant;
use cranelift_entity::EntityRef;
use std::collections::{BTreeMap, HashMap};
use std::vec::Vec;

/// This type describes the actual constant data.
pub type ConstantData = Vec<u8>;

/// This type describes an offset in bytes within a constant pool.
pub type ConstantOffset = u32;

/// Inner type for storing data and offset together in the constant pool. The offset is optional
/// because it must be set relative to the function code size (i.e. constants are emitted after the
/// function body); because the function is not yet compiled when constants are inserted,
/// [set_offset](ir::ConstantPool::set_offset) must be called once a constant's offset from the
/// beginning of the function is known (see [relaxation.rs](binemit::relaxation)).
#[derive(Clone)]
pub struct ConstantPoolEntry {
    data: ConstantData,
    offset: Option<ConstantOffset>,
}

impl ConstantPoolEntry {
    fn new(data: ConstantData) -> Self {
        ConstantPoolEntry { data, offset: None }
    }

    /// Return the size of the constant at this entry.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Assign a new offset to the constant at this entry.
    pub fn set_offset(&mut self, offset: ConstantOffset) {
        self.offset = Some(offset)
    }
}

/// Maintains the mapping between a constant handle (i.e. [Constant](ir::entities::Constant)) and
/// its constant data (i.e. [ConstantData](ir::constant::ConstantData)).
#[derive(Clone)]
pub struct ConstantPool {
    /// This mapping maintains the insertion order as long as Constants are created with sequentially increasing integers.
    handles_to_values: BTreeMap<Constant, ConstantPoolEntry>,
    /// This mapping is unordered (no need for lexicographic ordering) but allows us to map constant data back to handles.
    values_to_handles: HashMap<ConstantData, Constant>,
}

impl ConstantPool {
    /// Create a new constant pool instance.
    pub fn new() -> Self {
        ConstantPool {
            handles_to_values: BTreeMap::new(),
            values_to_handles: HashMap::new(),
        }
    }

    /// Empty the constant pool of all data.
    pub fn clear(&mut self) {
        self.handles_to_values.clear();
        self.values_to_handles.clear();
    }

    /// Insert constant data into the pool, returning a handle for later referencing; when constant
    /// data is inserted that is a duplicate of previous constant data, the existing handle will be
    /// returned.
    pub fn insert(&mut self, constant_value: ConstantData) -> Constant {
        if self.values_to_handles.contains_key(&constant_value) {
            self.values_to_handles
                .get(&constant_value)
                .expect("A constant handle must have a corresponding constant value; this is an implementation error in ConstantPool")
                .clone()
        } else {
            let constant_handle = Constant::new(self.len());
            self.values_to_handles
                .insert(constant_value.clone(), constant_handle.clone());
            self.handles_to_values.insert(
                constant_handle.clone(),
                ConstantPoolEntry::new(constant_value),
            );
            constant_handle
        }
    }

    /// Retrieve the constant data given a handle.
    pub fn get(&self, constant_handle: Constant) -> &ConstantData {
        assert!(self.handles_to_values.contains_key(&constant_handle));
        &self.handles_to_values
            .get(&constant_handle)
            .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?")
            .data
    }

    /// Assign an offset to a given constant, where the offset is the number of bytes from the
    /// beginning of the function to the beginning of the constant data inside the pool.
    pub fn set_offset(&mut self, constant_handle: Constant, constant_offset: ConstantOffset) {
        assert!(self.handles_to_values.contains_key(&constant_handle), "A constant handle must have already been inserted into the pool; perhaps a constant pool was created outside of the pool?");
        self.handles_to_values
            .entry(constant_handle)
            .and_modify(|e| e.offset = Some(constant_offset));
    }

    /// Retrieve the offset of a given constant, where the offset is the number of bytes from the
    /// beginning of the function to the beginning of the constant data inside the pool.
    pub fn get_offset(&self, constant_handle: Constant) -> ConstantOffset {
        self.handles_to_values.get(&constant_handle)
            .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?")
            .offset
            .expect("A constant offset has not yet been set; verify that `set_offset` has been called before this point")
    }

    /// Iterate over the constants in insertion order.
    pub fn iter(&self) -> impl Iterator<Item = (&Constant, &ConstantData)> {
        self.handles_to_values.iter().map(|(h, e)| (h, &e.data))
    }

    /// Iterate over mutable entries in the constant pool in insertion order.
    pub fn entries_mut(&mut self) -> impl Iterator<Item = &mut ConstantPoolEntry> {
        self.handles_to_values.values_mut()
    }

    /// Return the number of constants in the pool.
    pub fn len(&self) -> usize {
        self.handles_to_values.len()
    }

    /// Return the combined size of all of the constant values in the pool.
    pub fn byte_size(&self) -> usize {
        self.values_to_handles.keys().map(|c| c.len()).sum()
    }
}

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

    #[test]
    fn empty() {
        let sut = ConstantPool::new();
        assert_eq!(sut.len(), 0);
    }

    #[test]
    fn insert() {
        let mut sut = ConstantPool::new();
        sut.insert(vec![1, 2, 3]);
        sut.insert(vec![4, 5, 6]);
        assert_eq!(sut.len(), 2);
    }

    #[test]
    fn insert_duplicate() {
        let mut sut = ConstantPool::new();
        let a = sut.insert(vec![1, 2, 3]);
        sut.insert(vec![4, 5, 6]);
        let b = sut.insert(vec![1, 2, 3]);
        assert_eq!(a, b);
    }

    #[test]
    fn clear() {
        let mut sut = ConstantPool::new();
        sut.insert(vec![1, 2, 3]);
        assert_eq!(sut.len(), 1);

        sut.clear();
        assert_eq!(sut.len(), 0);
    }

    #[test]
    fn iteration_order() {
        let mut sut = ConstantPool::new();
        sut.insert(vec![1, 2, 3]);
        sut.insert(vec![4, 5, 6]);
        sut.insert(vec![1, 2, 3]);
        let data = sut.iter().map(|(_, v)| v).collect::<Vec<&ConstantData>>();
        assert_eq!(data, vec![&vec![1, 2, 3], &vec![4, 5, 6]]);
    }

    #[test]
    fn get() {
        let mut sut = ConstantPool::new();
        let data = vec![1, 2, 3];
        let handle = sut.insert(data.clone());
        assert_eq!(sut.get(handle), &data);
    }

    #[test]
    #[should_panic]
    fn get_nonexistent_constant() {
        let sut = ConstantPool::new();
        let a = Constant::with_number(42).unwrap();
        sut.get(a); // panics, only use constants returned by ConstantPool
    }

    #[test]
    fn get_offset() {
        let mut sut = ConstantPool::new();
        let a = sut.insert(vec![1]);
        sut.set_offset(a, 42);
        assert_eq!(sut.get_offset(a), 42)
    }

    #[test]
    #[should_panic]
    fn get_nonexistent_offset() {
        let mut sut = ConstantPool::new();
        let a = sut.insert(vec![1]);
        sut.get_offset(a); // panics, set_offset should have been called
    }
}
<commit_msg>Fix documentation warnings in ConstantPool<commit_after>//! Constants
//!
//! The constant pool defined here allows cranelift to avoid emitting the same constant multiple
//! times. As constants are inserted in the pool, a handle is returned; the handle is a cranelift
//! Entity. Inserting the same data multiple times will always return the same handle. Future work
//! could include: ensuring alignment of constants within the pool, bucketing constants by size.

use crate::ir::Constant;
use cranelift_entity::EntityRef;
use std::collections::{BTreeMap, HashMap};
use std::vec::Vec;

/// This type describes the actual constant data.
pub type ConstantData = Vec<u8>;

/// This type describes an offset in bytes within a constant pool.
pub type ConstantOffset = u32;

/// Inner type for storing data and offset together in the constant pool. The offset is optional
/// because it must be set relative to the function code size (i.e. constants are emitted after the
/// function body); because the function is not yet compiled when constants are inserted,
/// [`set_offset`](crate::ir::ConstantPool::set_offset) must be called once a constant's
/// offset from the beginning of the function is known (see
/// [`relaxation.rs`](crate::binemit::relaxation)).
#[derive(Clone)]
pub struct ConstantPoolEntry {
    data: ConstantData,
    offset: Option<ConstantOffset>,
}

impl ConstantPoolEntry {
    fn new(data: ConstantData) -> Self {
        ConstantPoolEntry { data, offset: None }
    }

    /// Return the size of the constant at this entry.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Assign a new offset to the constant at this entry.
    pub fn set_offset(&mut self, offset: ConstantOffset) {
        self.offset = Some(offset)
    }
}

/// Maintains the mapping between a constant handle (i.e.
/// [`Constant`](crate::ir::Constant)) and its constant data (i.e.
/// [`ConstantData`](crate::ir::ConstantData)).
#[derive(Clone)]
pub struct ConstantPool {
    /// This mapping maintains the insertion order as long as Constants are created with sequentially increasing integers.
    handles_to_values: BTreeMap<Constant, ConstantPoolEntry>,
    /// This mapping is unordered (no need for lexicographic ordering) but allows us to map constant data back to handles.
    values_to_handles: HashMap<ConstantData, Constant>,
}

impl ConstantPool {
    /// Create a new constant pool instance.
    pub fn new() -> Self {
        ConstantPool {
            handles_to_values: BTreeMap::new(),
            values_to_handles: HashMap::new(),
        }
    }

    /// Empty the constant pool of all data.
    pub fn clear(&mut self) {
        self.handles_to_values.clear();
        self.values_to_handles.clear();
    }

    /// Insert constant data into the pool, returning a handle for later referencing; when constant
    /// data is inserted that is a duplicate of previous constant data, the existing handle will be
    /// returned.
    pub fn insert(&mut self, constant_value: ConstantData) -> Constant {
        if self.values_to_handles.contains_key(&constant_value) {
            self.values_to_handles
                .get(&constant_value)
                .expect("A constant handle must have a corresponding constant value; this is an implementation error in ConstantPool")
                .clone()
        } else {
            let constant_handle = Constant::new(self.len());
            self.values_to_handles
                .insert(constant_value.clone(), constant_handle.clone());
            self.handles_to_values.insert(
                constant_handle.clone(),
                ConstantPoolEntry::new(constant_value),
            );
            constant_handle
        }
    }

    /// Retrieve the constant data given a handle.
    pub fn get(&self, constant_handle: Constant) -> &ConstantData {
        assert!(self.handles_to_values.contains_key(&constant_handle));
        &self.handles_to_values
            .get(&constant_handle)
            .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?")
            .data
    }

    /// Assign an offset to a given constant, where the offset is the number of bytes from the
    /// beginning of the function to the beginning of the constant data inside the pool.
    pub fn set_offset(&mut self, constant_handle: Constant, constant_offset: ConstantOffset) {
        assert!(self.handles_to_values.contains_key(&constant_handle), "A constant handle must have already been inserted into the pool; perhaps a constant pool was created outside of the pool?");
        self.handles_to_values
            .entry(constant_handle)
            .and_modify(|e| e.offset = Some(constant_offset));
    }

    /// Retrieve the offset of a given constant, where the offset is the number of bytes from the
    /// beginning of the function to the beginning of the constant data inside the pool.
    pub fn get_offset(&self, constant_handle: Constant) -> ConstantOffset {
        self.handles_to_values.get(&constant_handle)
            .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?")
            .offset
            .expect("A constant offset has not yet been set; verify that `set_offset` has been called before this point")
    }

    /// Iterate over the constants in insertion order.
    pub fn iter(&self) -> impl Iterator<Item = (&Constant, &ConstantData)> {
        self.handles_to_values.iter().map(|(h, e)| (h, &e.data))
    }

    /// Iterate over mutable entries in the constant pool in insertion order.
    pub fn entries_mut(&mut self) -> impl Iterator<Item = &mut ConstantPoolEntry> {
        self.handles_to_values.values_mut()
    }

    /// Return the number of constants in the pool.
    pub fn len(&self) -> usize {
        self.handles_to_values.len()
    }

    /// Return the combined size of all of the constant values in the pool.
    pub fn byte_size(&self) -> usize {
        self.values_to_handles.keys().map(|c| c.len()).sum()
    }
}

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

    #[test]
    fn empty() {
        let sut = ConstantPool::new();
        assert_eq!(sut.len(), 0);
    }

    #[test]
    fn insert() {
        let mut sut = ConstantPool::new();
        sut.insert(vec![1, 2, 3]);
        sut.insert(vec![4, 5, 6]);
        assert_eq!(sut.len(), 2);
    }

    #[test]
    fn insert_duplicate() {
        let mut sut = ConstantPool::new();
        let a = sut.insert(vec![1, 2, 3]);
        sut.insert(vec![4, 5, 6]);
        let b = sut.insert(vec![1, 2, 3]);
        assert_eq!(a, b);
    }

    #[test]
    fn clear() {
        let mut sut = ConstantPool::new();
        sut.insert(vec![1, 2, 3]);
        assert_eq!(sut.len(), 1);

        sut.clear();
        assert_eq!(sut.len(), 0);
    }

    #[test]
    fn iteration_order() {
        let mut sut = ConstantPool::new();
        sut.insert(vec![1, 2, 3]);
        sut.insert(vec![4, 5, 6]);
        sut.insert(vec![1, 2, 3]);
        let data = sut.iter().map(|(_, v)| v).collect::<Vec<&ConstantData>>();
        assert_eq!(data, vec![&vec![1, 2, 3], &vec![4, 5, 6]]);
    }

    #[test]
    fn get() {
        let mut sut = ConstantPool::new();
        let data = vec![1, 2, 3];
        let handle = sut.insert(data.clone());
        assert_eq!(sut.get(handle), &data);
    }

    #[test]
    #[should_panic]
    fn get_nonexistent_constant() {
        let sut = ConstantPool::new();
        let a = Constant::with_number(42).unwrap();
        sut.get(a); // panics, only use constants returned by ConstantPool
    }

    #[test]
    fn get_offset() {
        let mut sut = ConstantPool::new();
        let a = sut.insert(vec![1]);
        sut.set_offset(a, 42);
        assert_eq!(sut.get_offset(a), 42)
    }

    #[test]
    #[should_panic]
    fn get_nonexistent_offset() {
        let mut sut = ConstantPool::new();
        let a = sut.insert(vec![1]);
        sut.get_offset(a); // panics, set_offset should have been called
    }
}
<|endoftext|>


<commit_before>use crate::value::AMQPValue;

use std::{
    collections::{BTreeMap, btree_map},
    fmt,
};

use serde::{Deserialize, Serialize};

/// Enumeration referencing all the available AMQP types
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum AMQPType {
    /// A bool
    Boolean,
    /// An i8
    ShortShortInt,
    /// A u8
    ShortShortUInt,
    /// An i16
    ShortInt,
    /// A u16
    ShortUInt,
    /// An i32
    LongInt,
    /// A u32
    LongUInt,
    /// An i64
    LongLongInt,
    /// A u64
    LongLongUInt,
    /// An f32
    Float,
    /// An f64
    Double,
    /// A decimal value represented by a scale and a value
    DecimalValue,
    /// Deprecated, a String
    ShortString,
    /// A String
    LongString,
    /// An array of AMQPValue
    FieldArray,
    /// A timestamp (u32)
    Timestamp,
    /// A Map<String, AMQPValue>
    FieldTable,
    /// An array of bytes, RabbitMQ specific
    ByteArray, /* ByteArray is specific to RabbitMQ */
    /// No value
    Void,
}

impl AMQPType {
    /// Get the AMQPType corresponding to the given id.
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// 's' means ShortInt (like 'U') instead of ShortString
    /// 'l' and 'L' both mean LongLongInt (no LongLongUInt)
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    /// Get the id from an AMQPType
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// ShortString doesn't have an id, we return '_' instead
    /// ShortInt is supposed to be 'U' but we use 's'
    /// LongLongUInt is supposed to be 'L' but we return 'l' as LongLongInt
    pub fn get_id(self) -> char {
        match self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A bool
pub type Boolean        = bool;
/// An i8
pub type ShortShortInt  = i8;
/// A u8
pub type ShortShortUInt = u8;
/// An i16
pub type ShortInt       = i16;
/// A u16
pub type ShortUInt      = u16;
/// An i32
pub type LongInt        = i32;
/// A u32
pub type LongUInt       = u32;
/// An i64
pub type LongLongInt    = i64;
/// A u64
pub type LongLongUInt   = u64;
/// A f32
pub type Float          = f32;
/// A f64
pub type Double         = f64;
/// A timestamp (u32)
pub type Timestamp      = LongLongUInt;
/// No value
pub type Void           = ();

/// A String (deprecated)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct ShortString(String);
/// A String
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct LongString(String);
/// An array of AMQPValue
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldArray(Vec<AMQPValue>);
/// A Map<String, AMQPValue>
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldTable(BTreeMap<ShortString, AMQPValue>);
/// An array of bytes (RabbitMQ specific)
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct ByteArray(Vec<u8>);

/// A Decimal value composed of a scale and a value
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct DecimalValue {
    /// The scale of the value
    pub scale: ShortShortUInt,
    /// The actual value
    pub value: LongUInt,
}

/// A Reference pointing to a ShortString
pub struct ShortStringRef<'a>(pub &'a str);
/// A Reference pointing to a LongString
pub struct LongStringRef<'a>(pub &'a str);

impl<'a> ShortString {
    /// Get a reference to a ShortString
    pub fn as_ref(&'a self) -> ShortStringRef<'a> {
        ShortStringRef(&self.0)
    }
}

impl From<&str> for ShortString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl fmt::Display for ShortString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> ShortStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for ShortStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for ShortStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl<'a> LongString {
    /// Get a reference to a LongString
    pub fn as_ref(&'a self) -> LongStringRef<'a> {
        LongStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }
}

impl From<&str> for LongString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl fmt::Display for LongString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> LongStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for LongStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for LongStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl FieldArray {
    pub(crate) fn as_slice(&self) -> &[AMQPValue] {
        self.0.as_slice()
    }

    pub(crate) fn push(&mut self, v: AMQPValue) {
        self.0.push(v);
    }
}

impl From<Vec<AMQPValue>> for FieldArray {
    fn from(v: Vec<AMQPValue>) -> Self {
        Self(v)
    }
}

impl FieldTable {
    /// Insert a new entry in the table
    pub fn insert(&mut self, k: ShortString, v: AMQPValue) {
        self.0.insert(k, v);
    }

    pub(crate) fn iter(&self) -> btree_map::Iter<'_, ShortString, AMQPValue> {
        self.0.iter()
    }
}

impl<'a> IntoIterator for &'a FieldTable {
    type Item = (&'a ShortString, &'a AMQPValue);
    type IntoIter = btree_map::Iter<'a, ShortString, AMQPValue>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl From<BTreeMap<ShortString, AMQPValue>> for FieldTable {
    fn from(m: BTreeMap<ShortString, AMQPValue>) -> Self {
        Self(m)
    }
}

impl ByteArray {
    pub(crate) fn as_slice(&self) -> &[u8] {
        self.0.as_slice()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl From<Vec<u8>> for ByteArray {
    fn from(v: Vec<u8>) -> Self {
        Self(v)
    }
}

impl From<&[u8]> for ByteArray {
    fn from(v: &[u8]) -> Self {
        Self(v.to_vec())
    }
}

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

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<commit_msg>types: add missing trait impl<commit_after>use crate::value::AMQPValue;

use std::{
    collections::{BTreeMap, btree_map},
    borrow, fmt, str,
};

use serde::{Deserialize, Serialize};

/// Enumeration referencing all the available AMQP types
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum AMQPType {
    /// A bool
    Boolean,
    /// An i8
    ShortShortInt,
    /// A u8
    ShortShortUInt,
    /// An i16
    ShortInt,
    /// A u16
    ShortUInt,
    /// An i32
    LongInt,
    /// A u32
    LongUInt,
    /// An i64
    LongLongInt,
    /// A u64
    LongLongUInt,
    /// An f32
    Float,
    /// An f64
    Double,
    /// A decimal value represented by a scale and a value
    DecimalValue,
    /// Deprecated, a String
    ShortString,
    /// A String
    LongString,
    /// An array of AMQPValue
    FieldArray,
    /// A timestamp (u32)
    Timestamp,
    /// A Map<String, AMQPValue>
    FieldTable,
    /// An array of bytes, RabbitMQ specific
    ByteArray, /* ByteArray is specific to RabbitMQ */
    /// No value
    Void,
}

impl AMQPType {
    /// Get the AMQPType corresponding to the given id.
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// 's' means ShortInt (like 'U') instead of ShortString
    /// 'l' and 'L' both mean LongLongInt (no LongLongUInt)
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    /// Get the id from an AMQPType
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// ShortString doesn't have an id, we return '_' instead
    /// ShortInt is supposed to be 'U' but we use 's'
    /// LongLongUInt is supposed to be 'L' but we return 'l' as LongLongInt
    pub fn get_id(self) -> char {
        match self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A bool
pub type Boolean        = bool;
/// An i8
pub type ShortShortInt  = i8;
/// A u8
pub type ShortShortUInt = u8;
/// An i16
pub type ShortInt       = i16;
/// A u16
pub type ShortUInt      = u16;
/// An i32
pub type LongInt        = i32;
/// A u32
pub type LongUInt       = u32;
/// An i64
pub type LongLongInt    = i64;
/// A u64
pub type LongLongUInt   = u64;
/// A f32
pub type Float          = f32;
/// A f64
pub type Double         = f64;
/// A timestamp (u32)
pub type Timestamp      = LongLongUInt;
/// No value
pub type Void           = ();

/// A String (deprecated)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct ShortString(String);
/// A String
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct LongString(String);
/// An array of AMQPValue
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldArray(Vec<AMQPValue>);
/// A Map<String, AMQPValue>
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldTable(BTreeMap<ShortString, AMQPValue>);
/// An array of bytes (RabbitMQ specific)
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct ByteArray(Vec<u8>);

/// A Decimal value composed of a scale and a value
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct DecimalValue {
    /// The scale of the value
    pub scale: ShortShortUInt,
    /// The actual value
    pub value: LongUInt,
}

/// A Reference pointing to a ShortString
pub struct ShortStringRef<'a>(pub &'a str);
/// A Reference pointing to a LongString
pub struct LongStringRef<'a>(pub &'a str);

impl<'a> ShortString {
    /// Get a reference to a ShortString
    pub fn as_ref(&'a self) -> ShortStringRef<'a> {
        ShortStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }

    /// Splits a string slice by whitespace.
    pub fn split_whitespace(&'a self) -> str::SplitWhitespace<'a> {
        self.0.split_whitespace()
    }
}

impl From<&str> for ShortString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl borrow::Borrow<str> for ShortString {
    fn borrow(&self) -> &str {
        self.0.borrow()
    }
}

impl fmt::Display for ShortString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> ShortStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for ShortStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for ShortStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl<'a> LongString {
    /// Get a reference to a LongString
    pub fn as_ref(&'a self) -> LongStringRef<'a> {
        LongStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }

    /// Splits a string slice by whitespace.
    pub fn split_whitespace(&'a self) -> str::SplitWhitespace<'a> {
        self.0.split_whitespace()
    }
}

impl From<&str> for LongString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl borrow::Borrow<str> for LongString {
    fn borrow(&self) -> &str {
        self.0.borrow()
    }
}

impl fmt::Display for LongString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> LongStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for LongStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for LongStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl FieldArray {
    pub(crate) fn as_slice(&self) -> &[AMQPValue] {
        self.0.as_slice()
    }

    pub(crate) fn push(&mut self, v: AMQPValue) {
        self.0.push(v);
    }
}

impl From<Vec<AMQPValue>> for FieldArray {
    fn from(v: Vec<AMQPValue>) -> Self {
        Self(v)
    }
}

impl FieldTable {
    /// Insert a new entry in the table
    pub fn insert(&mut self, k: ShortString, v: AMQPValue) {
        self.0.insert(k, v);
    }

    /// Check whether the table contains the given key
    pub fn contains_key(&self, k: &str) -> bool {
        self.0.contains_key(k)
    }

    pub(crate) fn iter(&self) -> btree_map::Iter<'_, ShortString, AMQPValue> {
        self.0.iter()
    }
}

impl<'a> IntoIterator for &'a FieldTable {
    type Item = (&'a ShortString, &'a AMQPValue);
    type IntoIter = btree_map::Iter<'a, ShortString, AMQPValue>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl From<BTreeMap<ShortString, AMQPValue>> for FieldTable {
    fn from(m: BTreeMap<ShortString, AMQPValue>) -> Self {
        Self(m)
    }
}

impl ByteArray {
    pub(crate) fn as_slice(&self) -> &[u8] {
        self.0.as_slice()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl From<Vec<u8>> for ByteArray {
    fn from(v: Vec<u8>) -> Self {
        Self(v)
    }
}

impl From<&[u8]> for ByteArray {
    fn from(v: &[u8]) -> Self {
        Self(v.to_vec())
    }
}

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

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<|endoftext|>