<commit_before>use error::Error;
use ng::graph::{Dependency, Edge, Graph, Hierarchy, Module, Visibility, GLOB};

pub fn print(graph: &Graph, include_orphans: bool) -> Result<(), Error> {
    let indent_str: &str = "    ";
    let root_node: Module = find_root_module(&graph)?;

    println!(
        "digraph {{\n{}label=\"{}\";\npad=0.4;",
        indent_str,
        root_node.name()
    );

    println!("{}// Modules", indent_str);
    for module in graph.nodes().filter(|m| {
        // All modules if include_orhans is true,
        // else only non-orphaned modules.
        include_orphans || !m.is_orphan()
    }) {
        print!("{}", indent_str);
        print_node(module);
    }
    print!("\n");

    println!("{}// Hierarchy", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_hierarchy(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("{}// Dependencies", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_dependency(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("}}");
    Ok(())
}

fn find_root_module(graph: &Graph) -> Result<Module, Error> {
    let mut nodes = graph.nodes().filter(Module::is_root);
    match (nodes.next(), nodes.count()) {
        (None, _) => Err(Error::Graph("No root module found.".to_owned())),
        (Some(module), 0) => Ok(module),
        (Some(_), _) => Err(Error::Graph("There are multiple root modules.".to_owned())),
    }
}

fn format_dependency(from: Module, to: Module, edge: &Edge) -> Option<String> {
    if edge.dependency.is_empty() {
        None
    } else {
        match &edge.dependency {
            Dependency {
                refers_to_all,
                refers_to_mod,
                referred_members,
            } => {
                let color: &str = "azure3";
                // TODO: Set the overall font size manually as well, instead
                //       of relying on the default value.
                let font_size: u8 = 10;

                let mut label_parts: Vec<String> = Vec::new();
                if *refers_to_mod {
                    label_parts.push("self".to_owned());
                }
                if *refers_to_all {
                    label_parts.push(GLOB.to_owned());
                }
                let mut sorted_members = referred_members.iter().cloned().collect::<Vec<_>>();
                for member in sorted_members.drain(..) {
                    label_parts.push(member);
                }

                Some(format!(
                    "\"{}\" -> \"{}\" [weight=90, color={}, penwidth=2, label=<use {}>]",
                    from.path(),
                    to.path(),
                    color,
                    font_size,
                    color,
                    label_parts.join(", ")
                ))
            }
        }
    }
}

fn format_hierarchy(from: Module, to: Module, edge: &Edge) -> Option<String> {
    (match edge.hierarchy {
        Hierarchy::Child => Some("[weight=100, color=azure4, penwidth=3]"),
        Hierarchy::Orphan => Some("[weight=50, color=firebrick4, penwidth=1]"),
        Hierarchy::None => None,
    })
    .map(|edge_style| format!("\"{}\" -> \"{}\" {}", from.path(), to.path(), edge_style))
}

fn print_node(module: Module) {
    let (color, fill_color): (&str, &str) = match module.visibility() {
        Some(Visibility::Public) => ("green4", "greenyellow"),
        Some(Visibility::Private) => ("darkgoldenrod", "khaki1"),
        None => ("firebrick4", "rosybrown1"), // Module is orphaned
    };
    println!(
        "\"{}\" [label=\"{}\", color={}, fontcolor={} style=filled, fillcolor={}]",
        module.path(),
        module.name(),
        color,
        color,
        fill_color
    );
}
<commit_msg>Format additional graph attributes better<commit_after>use error::Error;
use ng::graph::{Dependency, Edge, Graph, Hierarchy, Module, Visibility, GLOB};

pub fn print(graph: &Graph, include_orphans: bool) -> Result<(), Error> {
    let indent_str: &str = "    ";
    let root_node: Module = find_root_module(&graph)?;

    println!(
        "digraph {{\n{}\n{}\n",
        format!("{}label=\"{}\";", indent_str, root_node.name()),
        format!("{}pad=0.4;", indent_str),
    );

    println!("{}// Modules", indent_str);
    for module in graph.nodes().filter(|m| {
        // All modules if include_orhans is true,
        // else only non-orphaned modules.
        include_orphans || !m.is_orphan()
    }) {
        print!("{}", indent_str);
        print_node(module);
    }
    print!("\n");

    println!("{}// Hierarchy", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_hierarchy(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("{}// Dependencies", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_dependency(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("}}");
    Ok(())
}

fn find_root_module(graph: &Graph) -> Result<Module, Error> {
    let mut nodes = graph.nodes().filter(Module::is_root);
    match (nodes.next(), nodes.count()) {
        (None, _) => Err(Error::Graph("No root module found.".to_owned())),
        (Some(module), 0) => Ok(module),
        (Some(_), _) => Err(Error::Graph("There are multiple root modules.".to_owned())),
    }
}

fn format_dependency(from: Module, to: Module, edge: &Edge) -> Option<String> {
    if edge.dependency.is_empty() {
        None
    } else {
        match &edge.dependency {
            Dependency {
                refers_to_all,
                refers_to_mod,
                referred_members,
            } => {
                let color: &str = "azure3";
                // TODO: Set the overall font size manually as well, instead
                //       of relying on the default value.
                let font_size: u8 = 10;

                let mut label_parts: Vec<String> = Vec::new();
                if *refers_to_mod {
                    label_parts.push("self".to_owned());
                }
                if *refers_to_all {
                    label_parts.push(GLOB.to_owned());
                }
                let mut sorted_members = referred_members.iter().cloned().collect::<Vec<_>>();
                for member in sorted_members.drain(..) {
                    label_parts.push(member);
                }

                Some(format!(
                    "\"{}\" -> \"{}\" [weight=90, color={}, penwidth=2, label=<use {}>]",
                    from.path(),
                    to.path(),
                    color,
                    font_size,
                    color,
                    label_parts.join(", ")
                ))
            }
        }
    }
}

fn format_hierarchy(from: Module, to: Module, edge: &Edge) -> Option<String> {
    (match edge.hierarchy {
        Hierarchy::Child => Some("[weight=100, color=azure4, penwidth=3]"),
        Hierarchy::Orphan => Some("[weight=50, color=firebrick4, penwidth=1]"),
        Hierarchy::None => None,
    })
    .map(|edge_style| format!("\"{}\" -> \"{}\" {}", from.path(), to.path(), edge_style))
}

fn print_node(module: Module) {
    let (color, fill_color): (&str, &str) = match module.visibility() {
        Some(Visibility::Public) => ("green4", "greenyellow"),
        Some(Visibility::Private) => ("darkgoldenrod", "khaki1"),
        None => ("firebrick4", "rosybrown1"), // Module is orphaned
    };
    println!(
        "\"{}\" [label=\"{}\", color={}, fontcolor={} style=filled, fillcolor={}]",
        module.path(),
        module.name(),
        color,
        color,
        fill_color
    );
}
<|endoftext|>


<commit_before>//! Processor state stored in the RFLAGS register.

#[cfg(feature = "instructions")]
pub use self::x86_64::*;

use bitflags::bitflags;

bitflags! {
    /// The RFLAGS register.
    pub struct RFlags: u64 {
        /// Processor feature identification flag.
        ///
        /// If this flag is modifiable, the CPU supports CPUID.
        const ID = 1 << 21;
        /// Indicates that an external, maskable interrupt is pending.
        ///
        /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual
        /// interrupts (CR4.PVI) are activated.
        const VIRTUAL_INTERRUPT_PENDING = 1 << 20;
        /// Virtual image of the INTERRUPT_FLAG bit.
        ///
        /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual
        /// interrupts (CR4.PVI) are activated.
        const VIRTUAL_INTERRUPT = 1 << 19;
        /// Enable automatic alignment checking if CR0.AM is set. Only works if CPL is 3.
        const ALIGNMENT_CHECK = 1 << 18;
        /// Enable the virtual-8086 mode.
        const VIRTUAL_8086_MODE = 1 << 17;
        /// Allows to restart an instruction following an instrucion breakpoint.
        const RESUME_FLAG = 1 << 16;
        /// Used by `iret` in hardware task switch mode to determine if current task is nested.
        const NESTED_TASK = 1 << 14;
        /// The high bit of the I/O Privilege Level field.
        ///
        /// Specifies the privilege level required for executing I/O address-space instructions.
        const IOPL_HIGH = 1 << 13;
        /// The low bit of the I/O Privilege Level field.
        ///
        /// Specifies the privilege level required for executing I/O address-space instructions.
        const IOPL_LOW = 1 << 12;
        /// Set by hardware to indicate that the sign bit of the result of the last signed integer
        /// operation differs from the source operands.
        const OVERFLOW_FLAG = 1 << 11;
        /// Determines the order in which strings are processed.
        const DIRECTION_FLAG = 1 << 10;
        /// Enable interrupts.
        const INTERRUPT_FLAG = 1 << 9;
        /// Enable single-step mode for debugging.
        const TRAP_FLAG = 1 << 8;
        /// Set by hardware if last arithmetic operation resulted in a negative value.
        const SIGN_FLAG = 1 << 7;
        /// Set by hardware if last arithmetic operation resulted in a zero value.
        const ZERO_FLAG = 1 << 6;
        /// Set by hardware if last arithmetic operation generated a carry ouf of bit 3 of the
        /// result.
        const AUXILIARY_CARRY_FLAG = 1 << 4;
        /// Set by hardware if last result has an even number of 1 bits (only for some operations).
        const PARITY_FLAG = 1 << 2;
        /// Set by hardware if last arithmetic operation generated a carry out of the
        /// most-significant bit of the result.
        const CARRY_FLAG = 1;
    }
}

#[cfg(feature = "instructions")]
mod x86_64 {
    use super::*;

    /// Returns the current value of the RFLAGS register.
    ///
    /// Drops any unknown bits.
    #[inline]
    pub fn read() -> RFlags {
        RFlags::from_bits_truncate(read_raw())
    }

    /// Returns the raw current value of the RFLAGS register.
    #[inline]
    pub fn read_raw() -> u64 {
        let r: u64;
        #[cfg(feature = "inline_asm")]
        unsafe {
            asm!("pushf; pop {}", out(reg) r)
        };

        #[cfg(not(feature = "inline_asm"))]
        unsafe {
            r = crate::asm::x86_64_asm_read_rflags();
        };

        r
    }

    /// Writes the RFLAGS register, preserves reserved bits.
    ///
    /// ## Safety
    ///
    /// Unsafe because undefined becavior can occur if certain flags are modified. For example,
    /// the `DF` flag must be unset in all Rust code. Also, modifying `CF`, `PF`, or any other
    /// flags also used by Rust/LLVM can result in undefined behavior too.
    #[inline]
    pub unsafe fn write(flags: RFlags) {
        let old_value = read_raw();
        let reserved = old_value & !(RFlags::all().bits());
        let new_value = reserved | flags.bits();

        write_raw(new_value);
    }

    /// Writes the RFLAGS register.
    ///
    /// Does not preserve any bits, including reserved bits.
    ///
    ///
    /// ## Safety
    ///
    /// Unsafe because undefined becavior can occur if certain flags are modified. For example,
    /// the `DF` flag must be unset in all Rust code. Also, modifying `CF`, `PF`, or any other
    /// flags also used by Rust/LLVM can result in undefined behavior too.
    #[inline]
    pub unsafe fn write_raw(val: u64) {
        #[cfg(feature = "inline_asm")]
        {
            // FIXME - There's probably a better way than saying we preserve the flags even though we actually don't
            asm!("push {}; popf", in(reg) val, options(preserves_flags))
        };

        #[cfg(not(feature = "inline_asm"))]
        {
            crate::asm::x86_64_asm_write_rflags(val)
        }
    }

    #[cfg(test)]
    mod test {
        use crate::registers::rflags::read;

        #[test]
        fn rflags_read() {
            let rflags = read();
            println!("{:#?}", rflags);
        }
    }
}
<commit_msg>Fix Clippy warnings<commit_after>//! Processor state stored in the RFLAGS register.

#[cfg(feature = "instructions")]
pub use self::x86_64::*;

use bitflags::bitflags;

bitflags! {
    /// The RFLAGS register.
    pub struct RFlags: u64 {
        /// Processor feature identification flag.
        ///
        /// If this flag is modifiable, the CPU supports CPUID.
        const ID = 1 << 21;
        /// Indicates that an external, maskable interrupt is pending.
        ///
        /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual
        /// interrupts (CR4.PVI) are activated.
        const VIRTUAL_INTERRUPT_PENDING = 1 << 20;
        /// Virtual image of the INTERRUPT_FLAG bit.
        ///
        /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual
        /// interrupts (CR4.PVI) are activated.
        const VIRTUAL_INTERRUPT = 1 << 19;
        /// Enable automatic alignment checking if CR0.AM is set. Only works if CPL is 3.
        const ALIGNMENT_CHECK = 1 << 18;
        /// Enable the virtual-8086 mode.
        const VIRTUAL_8086_MODE = 1 << 17;
        /// Allows to restart an instruction following an instrucion breakpoint.
        const RESUME_FLAG = 1 << 16;
        /// Used by `iret` in hardware task switch mode to determine if current task is nested.
        const NESTED_TASK = 1 << 14;
        /// The high bit of the I/O Privilege Level field.
        ///
        /// Specifies the privilege level required for executing I/O address-space instructions.
        const IOPL_HIGH = 1 << 13;
        /// The low bit of the I/O Privilege Level field.
        ///
        /// Specifies the privilege level required for executing I/O address-space instructions.
        const IOPL_LOW = 1 << 12;
        /// Set by hardware to indicate that the sign bit of the result of the last signed integer
        /// operation differs from the source operands.
        const OVERFLOW_FLAG = 1 << 11;
        /// Determines the order in which strings are processed.
        const DIRECTION_FLAG = 1 << 10;
        /// Enable interrupts.
        const INTERRUPT_FLAG = 1 << 9;
        /// Enable single-step mode for debugging.
        const TRAP_FLAG = 1 << 8;
        /// Set by hardware if last arithmetic operation resulted in a negative value.
        const SIGN_FLAG = 1 << 7;
        /// Set by hardware if last arithmetic operation resulted in a zero value.
        const ZERO_FLAG = 1 << 6;
        /// Set by hardware if last arithmetic operation generated a carry ouf of bit 3 of the
        /// result.
        const AUXILIARY_CARRY_FLAG = 1 << 4;
        /// Set by hardware if last result has an even number of 1 bits (only for some operations).
        const PARITY_FLAG = 1 << 2;
        /// Set by hardware if last arithmetic operation generated a carry out of the
        /// most-significant bit of the result.
        const CARRY_FLAG = 1;
    }
}

#[cfg(feature = "instructions")]
mod x86_64 {
    use super::*;

    /// Returns the current value of the RFLAGS register.
    ///
    /// Drops any unknown bits.
    #[inline]
    pub fn read() -> RFlags {
        RFlags::from_bits_truncate(read_raw())
    }

    /// Returns the raw current value of the RFLAGS register.
    #[inline]
    pub fn read_raw() -> u64 {
        let r: u64;
        #[cfg(feature = "inline_asm")]
        unsafe {
            asm!("pushf; pop {}", out(reg) r)
        };

        #[cfg(not(feature = "inline_asm"))]
        unsafe {
            r = crate::asm::x86_64_asm_read_rflags();
        };

        r
    }

    /// Writes the RFLAGS register, preserves reserved bits.
    ///
    /// ## Safety
    ///
    /// Unsafe because undefined becavior can occur if certain flags are modified. For example,
    /// the `DF` flag must be unset in all Rust code. Also, modifying `CF`, `PF`, or any other
    /// flags also used by Rust/LLVM can result in undefined behavior too.
    #[inline]
    pub unsafe fn write(flags: RFlags) {
        let old_value = read_raw();
        let reserved = old_value & !(RFlags::all().bits());
        let new_value = reserved | flags.bits();

        write_raw(new_value);
    }

    /// Writes the RFLAGS register.
    ///
    /// Does not preserve any bits, including reserved bits.
    ///
    ///
    /// ## Safety
    ///
    /// Unsafe because undefined becavior can occur if certain flags are modified. For example,
    /// the `DF` flag must be unset in all Rust code. Also, modifying `CF`, `PF`, or any other
    /// flags also used by Rust/LLVM can result in undefined behavior too.
    #[inline]
    pub unsafe fn write_raw(val: u64) {
        // FIXME - There's probably a better way than saying we preserve the flags even though we actually don't
        #[cfg(feature = "inline_asm")]
        asm!("push {}; popf", in(reg) val, options(preserves_flags));

        #[cfg(not(feature = "inline_asm"))]
        crate::asm::x86_64_asm_write_rflags(val);
    }

    #[cfg(test)]
    mod test {
        use crate::registers::rflags::read;

        #[test]
        fn rflags_read() {
            let rflags = read();
            println!("{:#?}", rflags);
        }
    }
}
<|endoftext|>


<commit_before>use futures::{self,Async};
use std::os::raw::{c_void,c_char};
use std::io;
use tokio_core::reactor::{Handle,Remote};

use cstr;
use evented::EventedDNSService;
use ffi;
use interface::Interface;
use raw;
use remote::GetRemote;

type CallbackFuture = ::future::ServiceFuture<RegisterResult>;

/// Set of [`RegisterFlag`](enum.RegisterFlag.html)s
///
/// Flags and sets can be combined with bitor (`|`), and bitand (`&`)
/// can be used to test whether a flag is part of a set.
#[derive(Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Hash)]
pub struct RegisterFlags(u8);

/// Flags used to register service
#[derive(Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)]
#[repr(u8)]
pub enum RegisterFlag {
	/// Indicates a name conflict should not get handled automatically.
	///
	/// See [`kDNSServiceFlagsNoAutoRename`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsnoautorename).
	NoAutoRename = 0,

	/// Indicates there might me multiple records with the given name, type and class.
	///
	/// See [`kDNSServiceFlagsShared`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsshared).
	Shared,

	/// Indicates the records with the given name, type and class is unique.
	///
	/// See [`kDNSServiceFlagsUnique`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsunique).
	Unique,
}

flags_ops!{RegisterFlags: u8: RegisterFlag:
	NoAutoRename,
	Shared,
	Unique,
}

flag_mapping!{RegisterFlags: RegisterFlag => ffi::DNSServiceFlags:
	NoAutoRename => ffi::FLAGS_NO_AUTO_RENAME,
	Shared => ffi::FLAGS_SHARED,
	Unique => ffi::FLAGS_UNIQUE,
}

/// Pending registration
///
/// Becomes invalid when the future completes; use the returned
/// [`Registration`](struct.Registration.html) instead.
#[must_use = "futures do nothing unless polled"]
pub struct Register(CallbackFuture);

impl futures::Future for Register {
	type Item = (Registration, RegisterResult);
	type Error = io::Error;

	fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
		match self.0.poll() {
			Ok(Async::Ready((service, item))) => Ok(Async::Ready((
				Registration(service),
				item
			))),
			Ok(Async::NotReady) => Ok(Async::NotReady),
			Err(e) => Err(e),
		}
	}
}

impl GetRemote for Register {
	fn remote(&self) -> &Remote {
		self.0.remote()
	}
}

/// Service registration result
///
/// See [`DNSServiceRegisterReply`](https://developer.apple.com/documentation/dnssd/dnsserviceregisterreply).
#[derive(Clone,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)]
pub struct RegisterResult{
	/// if [`NoAutoRename`](enum.RegisterFlag.html#variant.NoAutoRename)
	/// was set this is the original name, otherwise it might be
	/// different.
	pub name: String,
	///
	pub reg_type: String,
	///
	pub domain: String,
}

extern "C" fn register_callback(
	_sd_ref: ffi::DNSServiceRef,
	_flags: ffi::DNSServiceFlags,
	error_code: ffi::DNSServiceErrorType,
	name: *const c_char,
	reg_type: *const c_char,
	domain: *const c_char,
	context: *mut c_void
) {
	CallbackFuture::run_callback(context, error_code, || {
		let name = unsafe { cstr::from_cstr(name) }?;
		let reg_type = unsafe { cstr::from_cstr(reg_type) }?;
		let domain = unsafe { cstr::from_cstr(domain) }?;

		Ok(RegisterResult{
			name: name.to_string(),
			reg_type: reg_type.to_string(),
			domain: domain.to_string(),
		})
	});
}

/// Successful registration
///
/// On dropping the registration the service will be unregistered.
/// Registered [`Record`](struct.Record.html)s from this `Registration`
/// or the originating [`Register`](struct.Register.html) future will
/// keep the `Registration` alive.
pub struct Registration(EventedDNSService);

/// Optional data when registering a service; either use its default
/// value or customize it like:
///
/// ```
/// # use async_dnssd::ServiceData;
/// ServiceData {
///     txt: b"some text data",
///     .. Default::default()
/// };
/// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct ServiceData<'a> {
	/// flags for registration
	pub flags: RegisterFlags,
	/// interface to register service on
	pub interface: Interface,
	/// service name, defaults to hostname
	pub name: Option<&'a str>,
	/// domain on which to advertise the service
	pub domain: Option<&'a str>,
	/// the SRV target host name, defaults to local hostname(s).
	/// Address records are NOT automatically generated for other names.
	pub host: Option<&'a str>,
	/// The TXT record rdata. Empty RDATA is treated like `b"\0"`, i.e.
	/// a TXT record with a single empty string.
	pub txt: &'a [u8],
}

impl<'a> Default for ServiceData<'a> {
	fn default() -> Self {
		ServiceData {
			flags: RegisterFlags::default(),
			interface: Interface::default(),
			name: None,
			domain: None,
			host: None,
			txt: b"",
		}
	}
}

/// Register a service
///
/// * `reg_type`: the service type followed by the protocol, separated
///   by a dot (for example, "_ssh._tcp").  For details see
///   [`DNSServiceRegister`]
/// * `port`: The port (in native byte order) on which the service
///   accepts connections.  Pass 0 for a "placeholder" service.
/// * `data`: additional service data; `Default::default()` should be
///   fine usually.
/// * `handle`: the tokio event loop handle
///
/// See
/// [`DNSServiceRegister`](https://developer.apple.com/documentation/dnssd/1804733-dnsserviceregister).
///
/// # Example
///
/// ```no_run
/// # extern crate async_dnssd;
/// # extern crate tokio_core;
/// # use async_dnssd::register;
/// # #[deny(unused_must_use)]
/// # fn main() -> std::io::Result<()> {
/// let mut core = tokio_core::reactor::Core::new()?;
/// let handle = core.handle();
/// let registration = core.run(register("_ssh._tcp", 22, Default::default(), &handle)?)?;
/// # Ok(())
/// # }
/// ```
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn register(
	reg_type: &str,
	port: u16,
	data: ServiceData,
	handle: &Handle,
) -> io::Result<Register> {
	::init();

	let name = cstr::NullableCStr::from(&data.name)?;
	let reg_type = cstr::CStr::from(&reg_type)?;
	let domain = cstr::NullableCStr::from(&data.domain)?;
	let host = cstr::NullableCStr::from(&data.host)?;

	Ok(Register(CallbackFuture::new(handle, move |sender|
		raw::DNSService::register(
			data.flags.into(),
			data.interface.into_raw(),
			&name,
			&reg_type,
			&domain,
			&host,
			port.to_be(),
			data.txt,
			Some(register_callback),
			sender,
		)
	)?))
}

impl Register {
	/// Add a record to a registered service
	///
	/// See [`DNSServiceAddRecord`](https://developer.apple.com/documentation/dnssd/1804730-dnsserviceaddrecord)
	pub fn add_record(
		&self,
		rr_type: u16,
		rdata: &[u8],
		ttl: u32
	) -> io::Result<::Record> {
		Ok(super::new_record(self.0.service().add_record(
			0, /* no flags */
			rr_type,
			rdata,
			ttl
		)?))
	}

	/// Get [`Record`](struct.Record.html) handle for default TXT record
	/// associated with the service registration (e.g. to update it).
	///
	/// [`Record::keep`](struct.Record.html#method.keep) doesn't do
	/// anything useful on that handle.
	pub fn get_default_txt_record(&self) -> ::Record {
		super::new_record(self.0.service().get_default_txt_record())
	}
}

impl Registration {
	/// Add a record to a registered service
	///
	/// See [`DNSServiceAddRecord`](https://developer.apple.com/documentation/dnssd/1804730-dnsserviceaddrecord)
	pub fn add_record(
		&self,
		rr_type: u16,
		rdata: &[u8],
		ttl: u32
	) -> io::Result<::Record> {
		Ok(super::new_record(self.0.service().add_record(
			0, /* no flags */
			rr_type,
			rdata,
			ttl
		)?))
	}

	/// Get [`Record`](struct.Record.html) handle for default TXT record
	/// associated with the service registration (e.g. to update it).
	///
	/// [`Record::keep`](struct.Record.html#method.keep) doesn't do
	/// anything useful on that handle.
	pub fn get_default_txt_record(&self) -> ::Record {
		super::new_record(self.0.service().get_default_txt_record())
	}
}
<commit_msg>rename `ServiceData` to `RegisterData`<commit_after>use futures::{self,Async};
use std::os::raw::{c_void,c_char};
use std::io;
use tokio_core::reactor::{Handle,Remote};

use cstr;
use evented::EventedDNSService;
use ffi;
use interface::Interface;
use raw;
use remote::GetRemote;

type CallbackFuture = ::future::ServiceFuture<RegisterResult>;

/// Set of [`RegisterFlag`](enum.RegisterFlag.html)s
///
/// Flags and sets can be combined with bitor (`|`), and bitand (`&`)
/// can be used to test whether a flag is part of a set.
#[derive(Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Hash)]
pub struct RegisterFlags(u8);

/// Flags used to register service
#[derive(Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)]
#[repr(u8)]
pub enum RegisterFlag {
	/// Indicates a name conflict should not get handled automatically.
	///
	/// See [`kDNSServiceFlagsNoAutoRename`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsnoautorename).
	NoAutoRename = 0,

	/// Indicates there might me multiple records with the given name, type and class.
	///
	/// See [`kDNSServiceFlagsShared`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsshared).
	Shared,

	/// Indicates the records with the given name, type and class is unique.
	///
	/// See [`kDNSServiceFlagsUnique`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsunique).
	Unique,
}

flags_ops!{RegisterFlags: u8: RegisterFlag:
	NoAutoRename,
	Shared,
	Unique,
}

flag_mapping!{RegisterFlags: RegisterFlag => ffi::DNSServiceFlags:
	NoAutoRename => ffi::FLAGS_NO_AUTO_RENAME,
	Shared => ffi::FLAGS_SHARED,
	Unique => ffi::FLAGS_UNIQUE,
}

/// Pending registration
///
/// Becomes invalid when the future completes; use the returned
/// [`Registration`](struct.Registration.html) instead.
#[must_use = "futures do nothing unless polled"]
pub struct Register(CallbackFuture);

impl futures::Future for Register {
	type Item = (Registration, RegisterResult);
	type Error = io::Error;

	fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
		match self.0.poll() {
			Ok(Async::Ready((service, item))) => Ok(Async::Ready((
				Registration(service),
				item
			))),
			Ok(Async::NotReady) => Ok(Async::NotReady),
			Err(e) => Err(e),
		}
	}
}

impl GetRemote for Register {
	fn remote(&self) -> &Remote {
		self.0.remote()
	}
}

/// Service registration result
///
/// See [`DNSServiceRegisterReply`](https://developer.apple.com/documentation/dnssd/dnsserviceregisterreply).
#[derive(Clone,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)]
pub struct RegisterResult{
	/// if [`NoAutoRename`](enum.RegisterFlag.html#variant.NoAutoRename)
	/// was set this is the original name, otherwise it might be
	/// different.
	pub name: String,
	///
	pub reg_type: String,
	///
	pub domain: String,
}

extern "C" fn register_callback(
	_sd_ref: ffi::DNSServiceRef,
	_flags: ffi::DNSServiceFlags,
	error_code: ffi::DNSServiceErrorType,
	name: *const c_char,
	reg_type: *const c_char,
	domain: *const c_char,
	context: *mut c_void
) {
	CallbackFuture::run_callback(context, error_code, || {
		let name = unsafe { cstr::from_cstr(name) }?;
		let reg_type = unsafe { cstr::from_cstr(reg_type) }?;
		let domain = unsafe { cstr::from_cstr(domain) }?;

		Ok(RegisterResult{
			name: name.to_string(),
			reg_type: reg_type.to_string(),
			domain: domain.to_string(),
		})
	});
}

/// Successful registration
///
/// On dropping the registration the service will be unregistered.
/// Registered [`Record`](struct.Record.html)s from this `Registration`
/// or the originating [`Register`](struct.Register.html) future will
/// keep the `Registration` alive.
pub struct Registration(EventedDNSService);

/// Optional data when registering a service; either use its default
/// value or customize it like:
///
/// ```
/// # use async_dnssd::RegisterData;
/// RegisterData {
///     txt: b"some text data",
///     .. Default::default()
/// };
/// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct RegisterData<'a> {
	/// flags for registration
	pub flags: RegisterFlags,
	/// interface to register service on
	pub interface: Interface,
	/// service name, defaults to hostname
	pub name: Option<&'a str>,
	/// domain on which to advertise the service
	pub domain: Option<&'a str>,
	/// the SRV target host name, defaults to local hostname(s).
	/// Address records are NOT automatically generated for other names.
	pub host: Option<&'a str>,
	/// The TXT record rdata. Empty RDATA is treated like `b"\0"`, i.e.
	/// a TXT record with a single empty string.
	pub txt: &'a [u8],
}

impl<'a> Default for RegisterData<'a> {
	fn default() -> Self {
		RegisterData {
			flags: RegisterFlags::default(),
			interface: Interface::default(),
			name: None,
			domain: None,
			host: None,
			txt: b"",
		}
	}
}

/// Register a service
///
/// * `reg_type`: the service type followed by the protocol, separated
///   by a dot (for example, "_ssh._tcp").  For details see
///   [`DNSServiceRegister`]
/// * `port`: The port (in native byte order) on which the service
///   accepts connections.  Pass 0 for a "placeholder" service.
/// * `data`: additional service data; `Default::default()` should be
///   fine usually.
/// * `handle`: the tokio event loop handle
///
/// See
/// [`DNSServiceRegister`](https://developer.apple.com/documentation/dnssd/1804733-dnsserviceregister).
///
/// # Example
///
/// ```no_run
/// # extern crate async_dnssd;
/// # extern crate tokio_core;
/// # use async_dnssd::register;
/// # #[deny(unused_must_use)]
/// # fn main() -> std::io::Result<()> {
/// let mut core = tokio_core::reactor::Core::new()?;
/// let handle = core.handle();
/// let registration = core.run(register("_ssh._tcp", 22, Default::default(), &handle)?)?;
/// # Ok(())
/// # }
/// ```
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn register(
	reg_type: &str,
	port: u16,
	data: RegisterData,
	handle: &Handle,
) -> io::Result<Register> {
	::init();

	let name = cstr::NullableCStr::from(&data.name)?;
	let reg_type = cstr::CStr::from(&reg_type)?;
	let domain = cstr::NullableCStr::from(&data.domain)?;
	let host = cstr::NullableCStr::from(&data.host)?;

	Ok(Register(CallbackFuture::new(handle, move |sender|
		raw::DNSService::register(
			data.flags.into(),
			data.interface.into_raw(),
			&name,
			&reg_type,
			&domain,
			&host,
			port.to_be(),
			data.txt,
			Some(register_callback),
			sender,
		)
	)?))
}

impl Register {
	/// Add a record to a registered service
	///
	/// See [`DNSServiceAddRecord`](https://developer.apple.com/documentation/dnssd/1804730-dnsserviceaddrecord)
	pub fn add_record(
		&self,
		rr_type: u16,
		rdata: &[u8],
		ttl: u32
	) -> io::Result<::Record> {
		Ok(super::new_record(self.0.service().add_record(
			0, /* no flags */
			rr_type,
			rdata,
			ttl
		)?))
	}

	/// Get [`Record`](struct.Record.html) handle for default TXT record
	/// associated with the service registration (e.g. to update it).
	///
	/// [`Record::keep`](struct.Record.html#method.keep) doesn't do
	/// anything useful on that handle.
	pub fn get_default_txt_record(&self) -> ::Record {
		super::new_record(self.0.service().get_default_txt_record())
	}
}

impl Registration {
	/// Add a record to a registered service
	///
	/// See [`DNSServiceAddRecord`](https://developer.apple.com/documentation/dnssd/1804730-dnsserviceaddrecord)
	pub fn add_record(
		&self,
		rr_type: u16,
		rdata: &[u8],
		ttl: u32
	) -> io::Result<::Record> {
		Ok(super::new_record(self.0.service().add_record(
			0, /* no flags */
			rr_type,
			rdata,
			ttl
		)?))
	}

	/// Get [`Record`](struct.Record.html) handle for default TXT record
	/// associated with the service registration (e.g. to update it).
	///
	/// [`Record::keep`](struct.Record.html#method.keep) doesn't do
	/// anything useful on that handle.
	pub fn get_default_txt_record(&self) -> ::Record {
		super::new_record(self.0.service().get_default_txt_record())
	}
}
<|endoftext|>


<commit_before>/*
DIRECTED CONTEXT

In this example we will try to solve the problem:

    A farmer want to cross a river, using a boat with room for two objects.
    With him he has a wolf, a sheep, and some cabbage.
    If not watching, the wolf eats the sheep, and the sheep eats the cabbage.
    Find an upper bound of legal moves below 200.

We have 4 objects: Wolf, sheep, cabbage and the boat.
The wolf, sheep and cabbage can be in 3 locations: Side A, boat, side B.
The boat can be in 2 locations: Side A or side B.
This becomes a N-dimensional configuration space of dimensions `[3, 3, 3, 2]`.

A directed context space models how a configuration space can change by moving
one object into another state at a time.
Each position in the space is equivalent to one move.

When we construct a directed context space with dimension `[3, 3, 3, 2]`,
we get 378 moves. These are all possible ways the objects can move ignoring
all physical rules.

There is a rule for context spaces that information that is symmetric
or invariant for one object can be removed without loosing context.
The boat in this case can always move from one side to the other,
regardless the states of other objects.
Therefore, we can reduce the space to `[3, 3, 3]`.
This leaves us with 162 moves.

A side note: The amount of memory needed to store any rules for such a puzzle
is in worst case 162 bits, because each bit can tell us whether a move is legal
or not. This is the same information we get from rules.

*/

extern crate discrete;

use discrete::*;

fn main() {
    let context: DirectedContext<Data> = Construct::new();

    let object = ["wolf", "sheep", "cabbage"];
    let side = ["side A", "boat", "side B"];
    let dim = vec![3, 3, 3]; /* wolf, sheep, cabbage, boat */
    let count = context.count(&dim);
    for x in 0..count {
        let mut pos = (vec![], 0, 0);
        context.to_pos(&dim, x, &mut pos);

        println!("{:?}", pos);
        print!("the {} ", object[pos.1]);
        print!("went from {} ", side[pos.0[pos.1]]);
        println!("to {}", side[pos.2]);

        for i in 0..3 {
            let pos_state = pos.0[i];
            println!("{} is at {}", object[i], side[pos_state]);
        }
    }
    println!("count {}", count);
}
<commit_msg>Reduced to 120 moves<commit_after>/*
DIRECTED CONTEXT

In this example we will try to solve the problem:

    A farmer want to cross a river, using a boat with room for two objects.
    With him he has a wolf, a sheep, and some cabbage.
    If not watching, the wolf eats the sheep, and the sheep eats the cabbage.
    Find an upper bound of legal moves below 200.

We have 4 objects: Wolf, sheep, cabbage and the boat.
The wolf, sheep and cabbage can be in 3 locations: Side A, boat, side B.
The boat can be in 2 locations: Side A or side B.
This becomes a N-dimensional configuration space of dimensions `[3, 3, 3, 2]`.

A directed context space models how a configuration space can change by moving
one object into another state at a time.
Each position in the space is equivalent to one move.

When we construct a directed context space with dimension `[3, 3, 3, 2]`,
we get 378 moves. These are all possible ways the objects can move ignoring
all physical rules.

There is a rule for context spaces that information that is symmetric
or invariant for one object can be removed without loosing context.
The boat in this case can always move from one side to the other,
regardless the states of other objects.
Therefore, we can reduce the space to `[3, 3, 3]`.
This reduces to 162 moves.

Each object can only move from side A to side B by using the boat.
We can model a space with dimension `[2, 2, 2, 3]` where the last
dimension tells which item can use the boat.
This reduces to 120 moves.

A side note: The amount of memory needed to store any rules for such a puzzle
is in worst case 120 bits, because each bit can tell us whether a move is legal
or not. This is the same information we get from rules.

*/

extern crate discrete;

use discrete::*;

fn main() {
    let context: DirectedContext<Data> = Construct::new();

    let dim = vec![2, 2, 2, 3];
    let shorter_count = context.count(&dim);

    let object = ["wolf", "sheep", "cabbage"];
    let side = ["side A", "boat", "side B"];
    let dim = vec![3, 3, 3]; /* wolf, sheep, cabbage, boat */
    let count = context.count(&dim);
    for x in 0..count {
        let mut pos = (vec![], 0, 0);
        context.to_pos(&dim, x, &mut pos);

        println!("{:?}", pos);
        print!("the {} ", object[pos.1]);
        print!("went from {} ", side[pos.0[pos.1]]);
        println!("to {}", side[pos.2]);

        for i in 0..3 {
            let pos_state = pos.0[i];
            println!("{} is at {}", object[i], side[pos_state]);
        }
    }
    println!("count {}", count);

    println!("shorter_counter {}", shorter_count);
}
<|endoftext|>


<commit_before>use addressable::Addressable;
use addressable::AddressableUtil;

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

struct Registers {
	pc: u16,				// program counter
	ac: u8,					// accumulator
	x: u8,					// x register
	y: u8,					// y register
	sr: u8,					// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	sp: u8,					// stack pointer
}

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn addr<M: Addressable<u16>> (&self, cpu: &Mos6502<M>) -> u16 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos6510: Immediade operand is never targetted to an address"),
			Accumulator							=> fail!("mos6510: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.reg.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.reg.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.reg.y as u16,
			Indirect(addr)						=> cpu.mem.get_le(addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.reg.x) as u16,					// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.reg.y) as u16,					// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> cpu.mem.get_le((addr + cpu.reg.x) as u16),	// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = cpu.mem.get_le(addr as u16); iaddr + cpu.reg.y as u16 },
		}
	}

	fn get<M: Addressable<u16>> (&self, cpu: &Mos6502<M>) -> u8 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.reg.ac,
			Relative(_target)					=> fail!("mos6510: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu); cpu.mem.get(addr) },
		}
	}

	fn set<M: Addressable<u16>> (&self, cpu: &mut Mos6502<M>, val: u8) {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos6510: Immediate operand never sets a value"),
			Accumulator							=> cpu.reg.ac = val,
			Relative(_target)					=> fail!("mos6510: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu); cpu.mem.set(addr, val); },
		}
	}
}

pub struct Mos6502<M> {
	priv reg: Registers,					// internal CPU registers
	priv mem: M,							// memory as accessible to the CPU
}

impl<M: Addressable<u16>> Mos6502<M> {
	pub fn new (mem: M) -> Mos6502<M> {
		Mos6502 {
			reg: Registers { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0 },
			mem: mem,
		}
	}

	fn get_opcode (&self) -> u8 {
		self.mem.get(self.reg.pc)
	}

	fn get_argument<T: Int> (&self) -> T {
		self.mem.get_le(self.reg.pc + 1)
	}
}

pub struct Mos6510<M> {
	priv cpu: Mos6502<M>,					// Core CPU
	priv port_ddr: u8,						// CPU port data direction register
	priv port_dat: u8,						// CPU port data register
}

impl<M: Addressable<u16>> Mos6510<M> {
	pub fn new (mem: M) -> Mos6510<M> {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		Mos6510 { cpu: Mos6502::new(mem), port_ddr: 0, port_dat: 0 }
	}
}
<commit_msg>Added preliminary step method to CPUs<commit_after>use addressable::Addressable;
use addressable::AddressableUtil;

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

struct Registers {
	pc: u16,				// program counter
	ac: u8,					// accumulator
	x: u8,					// x register
	y: u8,					// y register
	sr: u8,					// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	sp: u8,					// stack pointer
}

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn addr<M: Addressable<u16>> (&self, cpu: &Mos6502<M>) -> u16 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos6510: Immediade operand is never targetted to an address"),
			Accumulator							=> fail!("mos6510: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.reg.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.reg.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.reg.y as u16,
			Indirect(addr)						=> cpu.mem.get_le(addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.reg.x) as u16,					// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.reg.y) as u16,					// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> cpu.mem.get_le((addr + cpu.reg.x) as u16),	// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = cpu.mem.get_le(addr as u16); iaddr + cpu.reg.y as u16 },
		}
	}

	fn get<M: Addressable<u16>> (&self, cpu: &Mos6502<M>) -> u8 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.reg.ac,
			Relative(_target)					=> fail!("mos6510: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu); cpu.mem.get(addr) },
		}
	}

	fn set<M: Addressable<u16>> (&self, cpu: &mut Mos6502<M>, val: u8) {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos6510: Immediate operand never sets a value"),
			Accumulator							=> cpu.reg.ac = val,
			Relative(_target)					=> fail!("mos6510: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu); cpu.mem.set(addr, val); },
		}
	}
}

pub struct Mos6502<M> {
	priv reg: Registers,					// internal CPU registers
	priv mem: M,							// memory as accessible to the CPU
}

impl<M: Addressable<u16>> Mos6502<M> {
	pub fn new (mem: M) -> Mos6502<M> {
		Mos6502 {
			reg: Registers { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0 },
			mem: mem,
		}
	}

	fn get_opcode (&self) -> u8 {
		self.mem.get(self.reg.pc)
	}

	fn get_argument<T: Int> (&self) -> T {
		self.mem.get_le(self.reg.pc + 1)
	}

	pub fn step (&mut self) -> uint {
		// TODO
		0
	}
}

pub struct Mos6510<M> {
	priv cpu: Mos6502<M>,					// Core CPU
	priv port_ddr: u8,						// CPU port data direction register
	priv port_dat: u8,						// CPU port data register
}

impl<M: Addressable<u16>> Mos6510<M> {
	pub fn new (mem: M) -> Mos6510<M> {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		Mos6510 { cpu: Mos6502::new(mem), port_ddr: 0, port_dat: 0 }
	}

	pub fn step (&mut self) -> uint {
		self.cpu.step()
	}
}
<|endoftext|>


<commit_before>// A variation on cares-epoll.rs
//
// Here we hide the use of epoll() behind a `Resolver` object.  We also
// transform the asynchronous c-ares interface into a synchronous one, by
// using a std::sync::mpsc::channel.
extern crate c_ares;
extern crate nix;

use self::nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollFlags,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::str;
use std::sync::{
    Arc,
    Condvar,
    Mutex,
    mpsc,
};
use std::thread;

struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    keep_going: Arc<(Mutex<bool>, Condvar)>,
    fd_handle: Option<thread::JoinHandle<()>>,
}

// A thread that keeps going processing file descriptors for c-ares, until it
// is asked to stop.
fn fd_handling_thread(
    ares_channel: &Mutex<c_ares::Channel>,
    keep_going: &(Mutex<bool>, Condvar)) {
    let (ref lock, ref cvar) = *keep_going;
    let mut carry_on = lock.lock().unwrap();
    while *carry_on {
        process_ares_fds(ares_channel);
        carry_on = cvar.wait(carry_on).unwrap();
    }
}

// Process file descriptors for c-ares, while it wants us to do so.
fn process_ares_fds(ares_channel: &Mutex<c_ares::Channel>) {
    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<c_ares::Socket>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        let sockets = ares_channel.lock().unwrap().get_sock();
        for (fd, readable, writable) in &sockets {
            let mut interest = EpollFlags::empty();
            if readable { interest |= EPOLLIN; }
            if writable { interest |= EPOLLOUT; }
            let mut event = EpollEvent::new(interest, fd as u64);
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &mut event).expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent::new(EpollFlags::empty(), 0);
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.lock().unwrap().process_fd(
                    c_ares::SOCKET_BAD,
                    c_ares::SOCKET_BAD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares.
                for event in &events[0..n] {
                    let active_fd = event.data() as c_ares::Socket;
                    let rfd = if (event.events() & EPOLLIN).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    let wfd = if (event.events() & EPOLLOUT).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    ares_channel.lock().unwrap().process_fd(rfd, wfd);
                }
            }
        }
    }
}

impl Resolver {
    // Create a new Resolver
    pub fn new() -> Resolver {
        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_flags(c_ares::Flags::STAYOPEN)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::with_options(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create a thread to handle file descriptors.
        #[allow(mutex_atomic)]
        let keep_going = Arc::new((Mutex::new(true), Condvar::new()));
        let fd_handle = thread::spawn({
            let locked_channel = Arc::clone(&locked_channel);
            let keep_going = Arc::clone(&keep_going);
            move || fd_handling_thread(&*locked_channel, &*keep_going)
        });

        Resolver {
            ares_channel: locked_channel,
            keep_going: keep_going,
            fd_handle: Some(fd_handle),
        }
    }

    fn wake_fd_thread(&self) {
        let (ref _lock, ref cvar) = *self.keep_going;
        cvar.notify_one();
    }

    // A blocking NS query.  Achieve this by having the callback send the
    // result to a std::sync::mpsc::channel, and waiting on that channel.
    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ns(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking PTR query.
    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ptr(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking TXT query.
    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_txt(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Kick the file descriptor thread to stop.
        let (ref lock, ref cvar) = *self.keep_going;
        {
            let mut carry_on = lock.lock().unwrap();
            *carry_on = false;
        }
        cvar.notify_one();

        // Wait for it to do so.
        if let Some(handle) = self.fd_handle.take() {
            handle.join().unwrap();
        }
    }
}

fn print_ns_results(result: c_ares::Result<c_ares::NSResults>) {
    match result {
        Err(e) => {
            println!("NS lookup failed with error '{}'", e.description());
        }
        Ok(ns_results) => {
            println!("Successful NS lookup...");
            for ns_result in ns_results.aliases() {
                println!("{}", ns_result);
            }
        }
    }
}

fn print_ptr_results(result: c_ares::Result<c_ares::PTRResults>) {
    match result {
        Err(e) => {
            println!("PTR lookup failed with error '{}'", e.description());
        }
        Ok(ptr_results) => {
            println!("Successful PTR lookup...");
            for ptr_result in ptr_results.aliases() {
                println!("{}", ptr_result);
            }
        }
    }
}

fn print_txt_results(result: c_ares::Result<c_ares::TXTResults>) {
    match result {
        Err(e) => {
            println!("TXT lookup failed with error '{}'", e.description());
        }
        Ok(txt_results) => {
            println!("Successful TXT lookup...");
            for txt_result in &txt_results {
                let text = str::from_utf8(txt_result.text())
                    .unwrap_or("<binary>");
                println!(
                    "record start: {}, text: {}",
                    txt_result.record_start(),
                    text);
            }
        }
    }
}

pub fn main() {
    // Create a Resolver.  Then make some requests.
    let resolver = Resolver::new();
    let result = resolver.query_ns("google.com");
    println!("");
    print_ns_results(result);

    let result = resolver.query_ptr("14.210.58.216.in-addr.arpa");
    println!("");
    print_ptr_results(result);

    let result = resolver.query_txt("google.com");
    println!("");
    print_txt_results(result);
}
<commit_msg>only clippy understands clippy's warnings<commit_after>// A variation on cares-epoll.rs
//
// Here we hide the use of epoll() behind a `Resolver` object.  We also
// transform the asynchronous c-ares interface into a synchronous one, by
// using a std::sync::mpsc::channel.
extern crate c_ares;
extern crate nix;

use self::nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollFlags,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::str;
use std::sync::{
    Arc,
    Condvar,
    Mutex,
    mpsc,
};
use std::thread;

struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    keep_going: Arc<(Mutex<bool>, Condvar)>,
    fd_handle: Option<thread::JoinHandle<()>>,
}

// A thread that keeps going processing file descriptors for c-ares, until it
// is asked to stop.
fn fd_handling_thread(
    ares_channel: &Mutex<c_ares::Channel>,
    keep_going: &(Mutex<bool>, Condvar)) {
    let (ref lock, ref cvar) = *keep_going;
    let mut carry_on = lock.lock().unwrap();
    while *carry_on {
        process_ares_fds(ares_channel);
        carry_on = cvar.wait(carry_on).unwrap();
    }
}

// Process file descriptors for c-ares, while it wants us to do so.
fn process_ares_fds(ares_channel: &Mutex<c_ares::Channel>) {
    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<c_ares::Socket>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        let sockets = ares_channel.lock().unwrap().get_sock();
        for (fd, readable, writable) in &sockets {
            let mut interest = EpollFlags::empty();
            if readable { interest |= EPOLLIN; }
            if writable { interest |= EPOLLOUT; }
            let mut event = EpollEvent::new(interest, fd as u64);
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &mut event).expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent::new(EpollFlags::empty(), 0);
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.lock().unwrap().process_fd(
                    c_ares::SOCKET_BAD,
                    c_ares::SOCKET_BAD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares.
                for event in &events[0..n] {
                    let active_fd = event.data() as c_ares::Socket;
                    let rfd = if (event.events() & EPOLLIN).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    let wfd = if (event.events() & EPOLLOUT).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    ares_channel.lock().unwrap().process_fd(rfd, wfd);
                }
            }
        }
    }
}

impl Resolver {
    // Create a new Resolver
    pub fn new() -> Resolver {
        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_flags(c_ares::Flags::STAYOPEN)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::with_options(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create a thread to handle file descriptors.
        #[cfg_attr(feature="cargo-clippy", allow(mutex_atomic))]
        let keep_going = Arc::new((Mutex::new(true), Condvar::new()));
        let fd_handle = thread::spawn({
            let locked_channel = Arc::clone(&locked_channel);
            let keep_going = Arc::clone(&keep_going);
            move || fd_handling_thread(&*locked_channel, &*keep_going)
        });

        Resolver {
            ares_channel: locked_channel,
            keep_going: keep_going,
            fd_handle: Some(fd_handle),
        }
    }

    fn wake_fd_thread(&self) {
        let (ref _lock, ref cvar) = *self.keep_going;
        cvar.notify_one();
    }

    // A blocking NS query.  Achieve this by having the callback send the
    // result to a std::sync::mpsc::channel, and waiting on that channel.
    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ns(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking PTR query.
    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ptr(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking TXT query.
    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_txt(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Kick the file descriptor thread to stop.
        let (ref lock, ref cvar) = *self.keep_going;
        {
            let mut carry_on = lock.lock().unwrap();
            *carry_on = false;
        }
        cvar.notify_one();

        // Wait for it to do so.
        if let Some(handle) = self.fd_handle.take() {
            handle.join().unwrap();
        }
    }
}

fn print_ns_results(result: c_ares::Result<c_ares::NSResults>) {
    match result {
        Err(e) => {
            println!("NS lookup failed with error '{}'", e.description());
        }
        Ok(ns_results) => {
            println!("Successful NS lookup...");
            for ns_result in ns_results.aliases() {
                println!("{}", ns_result);
            }
        }
    }
}

fn print_ptr_results(result: c_ares::Result<c_ares::PTRResults>) {
    match result {
        Err(e) => {
            println!("PTR lookup failed with error '{}'", e.description());
        }
        Ok(ptr_results) => {
            println!("Successful PTR lookup...");
            for ptr_result in ptr_results.aliases() {
                println!("{}", ptr_result);
            }
        }
    }
}

fn print_txt_results(result: c_ares::Result<c_ares::TXTResults>) {
    match result {
        Err(e) => {
            println!("TXT lookup failed with error '{}'", e.description());
        }
        Ok(txt_results) => {
            println!("Successful TXT lookup...");
            for txt_result in &txt_results {
                let text = str::from_utf8(txt_result.text())
                    .unwrap_or("<binary>");
                println!(
                    "record start: {}, text: {}",
                    txt_result.record_start(),
                    text);
            }
        }
    }
}

pub fn main() {
    // Create a Resolver.  Then make some requests.
    let resolver = Resolver::new();
    let result = resolver.query_ns("google.com");
    println!("");
    print_ns_results(result);

    let result = resolver.query_ptr("14.210.58.216.in-addr.arpa");
    println!("");
    print_ptr_results(result);

    let result = resolver.query_txt("google.com");
    println!("");
    print_txt_results(result);
}
<|endoftext|>


<commit_before>pub trait SafeToU8 {
    fn safe_to_u8(self) -> u8;
}

pub trait SafeToU16 {
    fn safe_to_u16(self) -> u16;
}

pub trait SafeToI32 {
    fn safe_to_i32(self) -> i32;
}

impl SafeToU8 for u16 {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as u16);
        self as u8
    }
}

impl SafeToU8 for u32 {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as u32);
        self as u8
    }
}

impl SafeToU8 for i32 {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as i32);
        self as u8
    }
}

impl SafeToU8 for usize {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as usize);
        self as u8
    }
}

impl SafeToU16 for u32 {
    fn safe_to_u16(self) -> u16 {
        dbg_assert!(self < ::std::u16::MAX as u32);
        self as u16
    }
}

impl SafeToU16 for i32 {
    fn safe_to_u16(self) -> u16 {
        dbg_assert!(self < ::std::u16::MAX as i32);
        self as u16
    }
}

impl SafeToU16 for usize {
    fn safe_to_u16(self) -> u16 {
        dbg_assert!(self < ::std::u16::MAX as usize);
        self as u16
    }
}

impl SafeToI32 for u32 {
    fn safe_to_i32(self) -> i32 {
        dbg_assert!(self < ::std::i32::MAX as u32);
        self as i32
    }
}

impl SafeToI32 for usize {
    fn safe_to_i32(self) -> i32 {
        dbg_assert!(self < ::std::i32::MAX as usize);
        self as i32
    }
}

pub fn write_leb_i32(buf: &mut Vec<u8>, mut v: i32) {
    // Super complex stuff. See the following:
    // https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer
    // http://llvm.org/doxygen/LEB128_8h_source.html#l00048

    let mut more = true;
    let negative = v < 0;
    let size = 32;
    while more {
        let mut byte = (v & 0b1111111) as u8; // get last 7 bits
        v >>= 7; // shift them away from the value
        if negative {
            v |= (!0 as i32) << (size - 7); // extend sign
        }
        let sign_bit = byte & (1 << 6);
        if (v == 0 && sign_bit == 0) || (v == -1 && sign_bit != 0) {
            more = false;
        }
        else {
            byte |= 0b10000000; // turn on MSB
        }
        buf.push(byte);
    }
}

pub fn write_leb_u32(buf: &mut Vec<u8>, mut v: u32) {
    loop {
        let mut byte = v as u8 & 0b01111111; // get last 7 bits
        v >>= 7; // shift them away from the value
        if v != 0 {
            byte |= 0b10000000; // turn on MSB
        }
        buf.push(byte);
        if v == 0 {
            break;
        }
    }
}

pub fn write_fixed_leb16_at_idx(vec: &mut Vec<u8>, idx: usize, x: u16) {
    dbg_assert!(x < (1 << 14)); // we have 14 bits of available space in 2 bytes for leb
    vec[idx    ] = ((x & 0b1111111) | 0b10000000) as u8;
    vec[idx + 1] = (x >> 7) as u8;
}

pub fn write_fixed_leb32_at_idx(vec: &mut Vec<u8>, idx: usize, x: u32) {
    dbg_assert!(x < (1 << 28)); // we have 28 bits of available space in 4 bytes for leb
    vec[idx    ] = (x       & 0b1111111) as u8 | 0b10000000;
    vec[idx + 1] = (x >> 7  & 0b1111111) as u8 | 0b10000000;
    vec[idx + 2] = (x >> 14 & 0b1111111) as u8 | 0b10000000;
    vec[idx + 3] = (x >> 21 & 0b1111111) as u8;
}

pub type PackedStr = (u64, u64, u64);

#[allow(dead_code)]
pub fn pack_str(s: &str) -> PackedStr {
    assert!(s.len() <= 16);
    let mut a: [u8; 24] = [0; 24];
    for (i, ch) in s.char_indices() {
        a[i] = ch as u8;
    }

    unsafe { ::std::mem::transmute(a) }
}

pub fn unpack_str(s: PackedStr) -> String {
    let mut buf = String::with_capacity(24);
    let bytes: [u8; 24] = unsafe { ::std::mem::transmute(s) };
    for i in 0..24 {
        if bytes[i] == 0 {
            break;
        }
        buf.push(bytes[i] as char);
    }
    buf
}

#[allow(dead_code)]
pub const DEBUG: bool = true;

#[cfg(target_arch = "wasm32")]
extern "C" {
    pub fn log_from_wasm(ptr: *const u8, len: usize);
    pub fn abort();
}

#[cfg(target_arch = "wasm32")]
use std::string::ToString;

#[cfg(target_arch = "wasm32")]
pub fn _log_to_js_console<T: ToString>(s: T) {
    let s: String = s.to_string();
    let len = s.len();
    unsafe { log_from_wasm(s.as_bytes().as_ptr(), len); }
}

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

    #[test]
    fn packed_strs() {
        let pstr = pack_str("foo");
        assert_eq!("foo", unpack_str(pstr));

        let pstr = pack_str("abcdefghijkl");
        assert_eq!("abcdefghijkl", unpack_str(pstr));
    }

}
<commit_msg>use cfg!(debug_assertions) to set DEBUG<commit_after>pub trait SafeToU8 {
    fn safe_to_u8(self) -> u8;
}

pub trait SafeToU16 {
    fn safe_to_u16(self) -> u16;
}

pub trait SafeToI32 {
    fn safe_to_i32(self) -> i32;
}

impl SafeToU8 for u16 {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as u16);
        self as u8
    }
}

impl SafeToU8 for u32 {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as u32);
        self as u8
    }
}

impl SafeToU8 for i32 {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as i32);
        self as u8
    }
}

impl SafeToU8 for usize {
    fn safe_to_u8(self) -> u8 {
        dbg_assert!(self < ::std::u8::MAX as usize);
        self as u8
    }
}

impl SafeToU16 for u32 {
    fn safe_to_u16(self) -> u16 {
        dbg_assert!(self < ::std::u16::MAX as u32);
        self as u16
    }
}

impl SafeToU16 for i32 {
    fn safe_to_u16(self) -> u16 {
        dbg_assert!(self < ::std::u16::MAX as i32);
        self as u16
    }
}

impl SafeToU16 for usize {
    fn safe_to_u16(self) -> u16 {
        dbg_assert!(self < ::std::u16::MAX as usize);
        self as u16
    }
}

impl SafeToI32 for u32 {
    fn safe_to_i32(self) -> i32 {
        dbg_assert!(self < ::std::i32::MAX as u32);
        self as i32
    }
}

impl SafeToI32 for usize {
    fn safe_to_i32(self) -> i32 {
        dbg_assert!(self < ::std::i32::MAX as usize);
        self as i32
    }
}

pub fn write_leb_i32(buf: &mut Vec<u8>, mut v: i32) {
    // Super complex stuff. See the following:
    // https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer
    // http://llvm.org/doxygen/LEB128_8h_source.html#l00048

    let mut more = true;
    let negative = v < 0;
    let size = 32;
    while more {
        let mut byte = (v & 0b1111111) as u8; // get last 7 bits
        v >>= 7; // shift them away from the value
        if negative {
            v |= (!0 as i32) << (size - 7); // extend sign
        }
        let sign_bit = byte & (1 << 6);
        if (v == 0 && sign_bit == 0) || (v == -1 && sign_bit != 0) {
            more = false;
        }
        else {
            byte |= 0b10000000; // turn on MSB
        }
        buf.push(byte);
    }
}

pub fn write_leb_u32(buf: &mut Vec<u8>, mut v: u32) {
    loop {
        let mut byte = v as u8 & 0b01111111; // get last 7 bits
        v >>= 7; // shift them away from the value
        if v != 0 {
            byte |= 0b10000000; // turn on MSB
        }
        buf.push(byte);
        if v == 0 {
            break;
        }
    }
}

pub fn write_fixed_leb16_at_idx(vec: &mut Vec<u8>, idx: usize, x: u16) {
    dbg_assert!(x < (1 << 14)); // we have 14 bits of available space in 2 bytes for leb
    vec[idx    ] = ((x & 0b1111111) | 0b10000000) as u8;
    vec[idx + 1] = (x >> 7) as u8;
}

pub fn write_fixed_leb32_at_idx(vec: &mut Vec<u8>, idx: usize, x: u32) {
    dbg_assert!(x < (1 << 28)); // we have 28 bits of available space in 4 bytes for leb
    vec[idx    ] = (x       & 0b1111111) as u8 | 0b10000000;
    vec[idx + 1] = (x >> 7  & 0b1111111) as u8 | 0b10000000;
    vec[idx + 2] = (x >> 14 & 0b1111111) as u8 | 0b10000000;
    vec[idx + 3] = (x >> 21 & 0b1111111) as u8;
}

pub type PackedStr = (u64, u64, u64);

#[allow(dead_code)]
pub fn pack_str(s: &str) -> PackedStr {
    assert!(s.len() <= 16);
    let mut a: [u8; 24] = [0; 24];
    for (i, ch) in s.char_indices() {
        a[i] = ch as u8;
    }

    unsafe { ::std::mem::transmute(a) }
}

pub fn unpack_str(s: PackedStr) -> String {
    let mut buf = String::with_capacity(24);
    let bytes: [u8; 24] = unsafe { ::std::mem::transmute(s) };
    for i in 0..24 {
        if bytes[i] == 0 {
            break;
        }
        buf.push(bytes[i] as char);
    }
    buf
}

#[allow(dead_code)]
pub const DEBUG: bool = cfg!(debug_assertions);

#[cfg(target_arch = "wasm32")]
extern "C" {
    pub fn log_from_wasm(ptr: *const u8, len: usize);
    pub fn abort();
}

#[cfg(target_arch = "wasm32")]
use std::string::ToString;

#[cfg(target_arch = "wasm32")]
pub fn _log_to_js_console<T: ToString>(s: T) {
    let s: String = s.to_string();
    let len = s.len();
    unsafe { log_from_wasm(s.as_bytes().as_ptr(), len); }
}

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

    #[test]
    fn packed_strs() {
        let pstr = pack_str("foo");
        assert_eq!("foo", unpack_str(pstr));

        let pstr = pack_str("abcdefghijkl");
        assert_eq!("abcdefghijkl", unpack_str(pstr));
    }

}
<|endoftext|>