<commit_before>extern crate cc;
extern crate fs_extra;
extern crate metadeps;

use std::env;
#[cfg(not(feature = "build-cmake"))]
use std::ffi::OsString;
use std::fs;
use std::path::PathBuf;
#[cfg(not(feature = "build-cmake"))]
use std::process::Command;

fn main() {
    // Rerun if the c-ares source code has changed.
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=c-ares");

    // Use the installed libcares if it is available.
    if metadeps::probe().is_ok() {
        return;
    }

    // We'll compile from source.  Clean up previous build, if any.
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = outdir.join("build");
    let _ = fs::remove_dir_all(&build);
    fs::create_dir(&build).unwrap();

    // Copy the c-ares source code into $OUT_DIR, where it's safe for the build
    // process to modify it.
    let c_ares_dir = outdir.join("c-ares");
    let _ = fs::remove_dir_all(&c_ares_dir);
    let copy_options = fs_extra::dir::CopyOptions::new();
    let src = env::current_dir().unwrap().join("c-ares");
    fs_extra::dir::copy(&src, &outdir, &copy_options).unwrap();

    // Export the include path for crates dependending on c-ares
    println!("cargo:include={}", c_ares_dir.join("include").display());

    compile();
}

#[cfg(feature = "build-cmake")]
fn compile() {
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let c_ares_dir = outdir.join("c-ares");
    let dst = cmake::Config::new(c_ares_dir)
        .define("CARES_STATIC", "ON")
        .define("CARES_SHARED", "OFF")
        .define("CARES_BUILD_TOOLS", "OFF")
        .define("CMAKE_INSTALL_LIBDIR", "lib")
        .build();

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=cares");
}

#[cfg(not(feature = "build-cmake"))]
fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    match cmd.status() {
        Ok(t) => assert!(t.success()),
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    }
}

#[cfg(not(feature = "build-cmake"))]
fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {
        "gmake"
    } else {
        "make"
    }
}

#[cfg(not(feature = "build-cmake"))]
fn nmake(target: &str) -> Command {
    // cargo messes with the environment in a way that nmake does not like -
    // see https://github.com/rust-lang/cargo/issues/4156.  Explicitly remove
    // the unwanted variables.
    let mut cmd = cc::windows_registry::find(target, "nmake.exe").unwrap();
    cmd.env_remove("MAKEFLAGS").env_remove("MFLAGS");
    cmd
}

#[cfg(not(feature = "build-cmake"))]
fn compile() {
    // MSVC builds are different.
    let target = env::var("TARGET").unwrap();
    if target.contains("msvc") {
        build_msvc(&target);
        return;
    }

    // Prepare.
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let c_ares_dir = outdir.join("c-ares");
    let build = outdir.join("build");
    run(Command::new("sh").current_dir(&c_ares_dir).arg("buildconf"));

    // Configure.
    let cfg = cc::Build::new();
    let compiler = cfg.get_compiler();
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    let mut cmd = Command::new("sh");
    cmd.env("CFLAGS", &cflags)
        .env("CC", compiler.path())
        .current_dir(&build)
        .arg(format!("{}", c_ares_dir.join("configure").display()))
        .arg("--enable-static")
        .arg("--disable-shared")
        .arg("--enable-optimize")
        .arg("--disable-debug")
        .arg("--disable-tests")
        .arg(format!("--prefix={}", outdir.display()));

    // This code fragment copied from curl-rust... c-ares and curl come from
    // the same developer so are usually pretty similar, and this seems to
    // work.
    //
    // NOTE GNU terminology
    // BUILD = machine where we are (cross) compiling
    // HOST = machine where the compiled binary will be used
    // TARGET = only relevant when compiling compilers
    let host = env::var("HOST").unwrap();
    if target != host && (!target.contains("windows") || !host.contains("windows")) {
        if target.contains("windows") {
            cmd.arg(format!("--host={}", host));
            cmd.arg(format!("--target={}", target));
        } else {
            cmd.arg(format!("--build={}", host));
            cmd.arg(format!("--host={}", target));
        }
    }
    run(&mut cmd);

    // Compile.
    run(Command::new(make())
        .arg(format!("-j{}", env::var("NUM_JOBS").unwrap()))
        .current_dir(&build));

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/src/lib/.libs", build.display());
    println!("cargo:rustc-link-lib=static=cares");
}

#[cfg(not(feature = "build-cmake"))]
fn build_msvc(target: &str) {
    // Prepare.  We've already copied the c-ares source code into the output
    // directory.
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let c_ares_dir = outdir.join("c-ares");
    run(Command::new("cmd")
        .current_dir(&c_ares_dir)
        .arg("/c")
        .arg("buildconf.bat"));

    // Compile.
    let mut cmd = nmake(target);
    cmd.current_dir(&c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "CFG=lib-release", "c-ares"]);
    run(&mut cmd);

    // Install library.
    let build = outdir.join("build");
    let mut cmd = nmake(target);
    cmd.current_dir(&c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "/a", "CFG=lib-release", "install"]);
    cmd.env("INSTALL_DIR", format!("{}", build.display()));
    run(&mut cmd);

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/lib", build.display());
    println!("cargo:rustc-link-lib=iphlpapi");
    println!("cargo:rustc-link-lib=static=libcares");
}
<commit_msg>remove rerun-if-changed=build.rs<commit_after>extern crate cc;
extern crate fs_extra;
extern crate metadeps;

use std::env;
#[cfg(not(feature = "build-cmake"))]
use std::ffi::OsString;
use std::fs;
use std::path::PathBuf;
#[cfg(not(feature = "build-cmake"))]
use std::process::Command;

fn main() {
    // Rerun if the c-ares source code has changed.
    println!("cargo:rerun-if-changed=c-ares");

    // Use the installed libcares if it is available.
    if metadeps::probe().is_ok() {
        return;
    }

    // We'll compile from source.  Clean up previous build, if any.
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = outdir.join("build");
    let _ = fs::remove_dir_all(&build);
    fs::create_dir(&build).unwrap();

    // Copy the c-ares source code into $OUT_DIR, where it's safe for the build
    // process to modify it.
    let c_ares_dir = outdir.join("c-ares");
    let _ = fs::remove_dir_all(&c_ares_dir);
    let copy_options = fs_extra::dir::CopyOptions::new();
    let src = env::current_dir().unwrap().join("c-ares");
    fs_extra::dir::copy(&src, &outdir, &copy_options).unwrap();

    // Export the include path for crates dependending on c-ares
    println!("cargo:include={}", c_ares_dir.join("include").display());

    compile();
}

#[cfg(feature = "build-cmake")]
fn compile() {
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let c_ares_dir = outdir.join("c-ares");
    let dst = cmake::Config::new(c_ares_dir)
        .define("CARES_STATIC", "ON")
        .define("CARES_SHARED", "OFF")
        .define("CARES_BUILD_TOOLS", "OFF")
        .define("CMAKE_INSTALL_LIBDIR", "lib")
        .build();

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=cares");
}

#[cfg(not(feature = "build-cmake"))]
fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    match cmd.status() {
        Ok(t) => assert!(t.success()),
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    }
}

#[cfg(not(feature = "build-cmake"))]
fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {
        "gmake"
    } else {
        "make"
    }
}

#[cfg(not(feature = "build-cmake"))]
fn nmake(target: &str) -> Command {
    // cargo messes with the environment in a way that nmake does not like -
    // see https://github.com/rust-lang/cargo/issues/4156.  Explicitly remove
    // the unwanted variables.
    let mut cmd = cc::windows_registry::find(target, "nmake.exe").unwrap();
    cmd.env_remove("MAKEFLAGS").env_remove("MFLAGS");
    cmd
}

#[cfg(not(feature = "build-cmake"))]
fn compile() {
    // MSVC builds are different.
    let target = env::var("TARGET").unwrap();
    if target.contains("msvc") {
        build_msvc(&target);
        return;
    }

    // Prepare.
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let c_ares_dir = outdir.join("c-ares");
    let build = outdir.join("build");
    run(Command::new("sh").current_dir(&c_ares_dir).arg("buildconf"));

    // Configure.
    let cfg = cc::Build::new();
    let compiler = cfg.get_compiler();
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    let mut cmd = Command::new("sh");
    cmd.env("CFLAGS", &cflags)
        .env("CC", compiler.path())
        .current_dir(&build)
        .arg(format!("{}", c_ares_dir.join("configure").display()))
        .arg("--enable-static")
        .arg("--disable-shared")
        .arg("--enable-optimize")
        .arg("--disable-debug")
        .arg("--disable-tests")
        .arg(format!("--prefix={}", outdir.display()));

    // This code fragment copied from curl-rust... c-ares and curl come from
    // the same developer so are usually pretty similar, and this seems to
    // work.
    //
    // NOTE GNU terminology
    // BUILD = machine where we are (cross) compiling
    // HOST = machine where the compiled binary will be used
    // TARGET = only relevant when compiling compilers
    let host = env::var("HOST").unwrap();
    if target != host && (!target.contains("windows") || !host.contains("windows")) {
        if target.contains("windows") {
            cmd.arg(format!("--host={}", host));
            cmd.arg(format!("--target={}", target));
        } else {
            cmd.arg(format!("--build={}", host));
            cmd.arg(format!("--host={}", target));
        }
    }
    run(&mut cmd);

    // Compile.
    run(Command::new(make())
        .arg(format!("-j{}", env::var("NUM_JOBS").unwrap()))
        .current_dir(&build));

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/src/lib/.libs", build.display());
    println!("cargo:rustc-link-lib=static=cares");
}

#[cfg(not(feature = "build-cmake"))]
fn build_msvc(target: &str) {
    // Prepare.  We've already copied the c-ares source code into the output
    // directory.
    let outdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let c_ares_dir = outdir.join("c-ares");
    run(Command::new("cmd")
        .current_dir(&c_ares_dir)
        .arg("/c")
        .arg("buildconf.bat"));

    // Compile.
    let mut cmd = nmake(target);
    cmd.current_dir(&c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "CFG=lib-release", "c-ares"]);
    run(&mut cmd);

    // Install library.
    let build = outdir.join("build");
    let mut cmd = nmake(target);
    cmd.current_dir(&c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "/a", "CFG=lib-release", "install"]);
    cmd.env("INSTALL_DIR", format!("{}", build.display()));
    run(&mut cmd);

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/lib", build.display());
    println!("cargo:rustc-link-lib=iphlpapi");
    println!("cargo:rustc-link-lib=static=libcares");
}
<|endoftext|>


<commit_before>use std::{collections::VecDeque, io::SeekFrom};

use log::{debug, error, trace};
use nom::{self, Err, IResult, Needed, Offset};

use av_data::{
    audiosample::ChannelMap, packet::Packet, params::*, rational::Rational64, timeinfo::TimeInfo,
};
use av_format::{
    buffer::Buffered,
    common::GlobalInfo,
    demuxer::{Demuxer, Descr, Descriptor, Event},
    error::*,
    stream::Stream,
};

use crate::{
    ebml::{self, custom_error, ebml_header, EBMLHeader},
    elements::{
        segment, segment_element, simple_block, Audio, Cluster, Info, SeekHead, SegmentElement,
        TrackEntry, Tracks,
    },
};

#[derive(Debug, Clone, Default)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
    pub params: Option<DemuxerParams>,
}

#[derive(Debug, Clone, Default)]
pub struct DemuxerParams {
    pub track_numbers: Option<Vec<u64>>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
            params: None,
        }
    }

    pub fn with_params(params: DemuxerParams) -> MkvDemuxer {
        MkvDemuxer {
            params: Some(params),
            ..Default::default()
        }
    }

    pub fn parse_until_tracks<'a>(
        &mut self,
        original_input: &'a [u8],
    ) -> IResult<&'a [u8], (), ebml::Error<'a>> {
        let (i1, header) = ebml_header(original_input)?;

        self.header = Some(header);

        let (mut input, _) = segment(i1)?;

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            let (i3, element) = segment_element(input)?;

            match element {
                SegmentElement::SeekHead(s) => {
                    trace!("got seek head: {:#?}", s);
                    self.seek_head = if self.seek_head.is_none() {
                        Some(s)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Info(i) => {
                    trace!("got info: {:#?}", i);
                    self.info = if self.info.is_none() {
                        Some(i)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Tracks(t) => {
                    trace!("got tracks: {:#?}", t);
                    self.tracks = if self.tracks.is_none() {
                        // Only keep tracks we're interested in
                        if let Some(params) = &self.params {
                            if let Some(track_numbers) = &params.track_numbers {
                                let mut t = t;
                                t.tracks = t
                                    .tracks
                                    .into_iter()
                                    .filter(|tr| track_numbers.contains(&tr.track_number))
                                    .collect();
                                Some(t)
                            } else {
                                None
                            }
                        } else {
                            None
                        }
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                el => {
                    debug!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<dyn Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self
                    .info
                    .as_ref()
                    .and_then(|info| info.duration)
                    .map(|d| d as u64);
                if let Some(ref mut t) = self.tracks {
                    for tr in t.tracks.iter_mut() {
                        info.add_stream(track_to_stream(self.info.as_ref().unwrap(), tr));
                        tr.stream_index = info.streams.last().unwrap().index;
                    }
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            }
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + usize::from(size),
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            }
            e => {
                error!("{:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            debug!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets(self.tracks.as_ref().unwrap());
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {}
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                }
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(usize::from(size)))
                }
                e => {
                    error!("{:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1" => Some("av1".to_owned()),
        "V_VP8" => Some("vp8".to_owned()),
        "V_VP9" => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(audio: &Audio) -> Option<MediaKind> {
    let rate = if let Some(r) = audio.output_sampling_frequency {
        r
    } else {
        audio.sampling_frequency
    };
    // TODO: complete it
    let map = if audio.channel_positions.is_none() {
        Some(ChannelMap::default_map(audio.channels as usize))
    } else {
        unimplemented!("Convert matroska map to rust-av map")
    };
    let a = AudioInfo {
        rate: rate as usize,
        map,
        format: None,
    };
    Some(MediaKind::Audio(a))
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => {
            if let Some(ref audio) = t.audio {
                track_entry_audio_kind(audio)
            } else {
                None
            }
        }
        _ => None,
    }
}

pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = t
        .track_timecode_scale
        .map(|ts| {
            if ts != 0. {
                (ts * info.timecode_scale as f64) as i64
            } else {
                info.timecode_scale as i64
            }
        })
        .unwrap_or(info.timecode_scale as i64);

    Stream {
        id: t.track_uid as isize,
        index: t.stream_index,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
        user_private: None,
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self, tracks: &Tracks) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                debug!("parsing simple block: {:?}", block);
                if let Some(index) = tracks.lookup(block.track_number) {
                    let packet = Packet {
                        data: i.into(),
                        t: TimeInfo {
                            pts: Some(i64::from(block.timecode)),
                            dts: None,
                            duration: None,
                            timebase: None,
                            user_private: None,
                        },
                        pos: None,
                        stream_index: index as isize,
                        is_key: block.keyframe,
                        is_corrupted: false,
                    };

                    v.push(Event::NewPacket(packet));
                }
            } else {
                error!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<dyn Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe(&self) -> &Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        ebml_header(&data[..100]).map(|_| 100).unwrap_or(0)
    }
}

pub const MKV_DESC: &dyn Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    },
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use std::io::Cursor;

    use log::info;
    use nom::Offset;

    use av_format::{buffer::*, demuxer::Context};

    use super::*;

    const webm: &[u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        info!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                info!("offset: {} bytes", webm.offset(i));
            }
            e => {
                info!("could not parse: {:?}", e);
            }
        }

        info!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => info!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => info!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(
            Box::new(MkvDemuxer::new()),
            Box::new(AccReader::new(Cursor::new(webm))),
        );
        info!("read headers: {:?}", context.read_headers().unwrap());
        info!("streams: {:?}", context.info.streams);
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
    }
}
<commit_msg>Validate track_video existence before<commit_after>use std::{collections::VecDeque, io::SeekFrom};

use log::{debug, error, trace};
use nom::{self, Err, IResult, Needed, Offset};

use av_data::{
    audiosample::ChannelMap, packet::Packet, params::*, rational::Rational64, timeinfo::TimeInfo,
};
use av_format::{
    buffer::Buffered,
    common::GlobalInfo,
    demuxer::{Demuxer, Descr, Descriptor, Event},
    error::*,
    stream::Stream,
};

use crate::{
    ebml::{self, custom_error, ebml_header, EBMLHeader},
    elements::{
        segment, segment_element, simple_block, Audio, Cluster, Info, SeekHead, SegmentElement,
        TrackEntry, Tracks, Video,
    },
};

#[derive(Debug, Clone, Default)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
    pub params: Option<DemuxerParams>,
}

#[derive(Debug, Clone, Default)]
pub struct DemuxerParams {
    pub track_numbers: Option<Vec<u64>>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
            params: None,
        }
    }

    pub fn with_params(params: DemuxerParams) -> MkvDemuxer {
        MkvDemuxer {
            params: Some(params),
            ..Default::default()
        }
    }

    pub fn parse_until_tracks<'a>(
        &mut self,
        original_input: &'a [u8],
    ) -> IResult<&'a [u8], (), ebml::Error<'a>> {
        let (i1, header) = ebml_header(original_input)?;

        self.header = Some(header);

        let (mut input, _) = segment(i1)?;

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            let (i3, element) = segment_element(input)?;

            match element {
                SegmentElement::SeekHead(s) => {
                    trace!("got seek head: {:#?}", s);
                    self.seek_head = if self.seek_head.is_none() {
                        Some(s)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Info(i) => {
                    trace!("got info: {:#?}", i);
                    self.info = if self.info.is_none() {
                        Some(i)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Tracks(t) => {
                    trace!("got tracks: {:#?}", t);
                    self.tracks = if self.tracks.is_none() {
                        // Only keep tracks we're interested in
                        if let Some(params) = &self.params {
                            if let Some(track_numbers) = &params.track_numbers {
                                let mut t = t;
                                t.tracks = t
                                    .tracks
                                    .into_iter()
                                    .filter(|tr| track_numbers.contains(&tr.track_number))
                                    .collect();
                                Some(t)
                            } else {
                                None
                            }
                        } else {
                            None
                        }
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                el => {
                    debug!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<dyn Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self
                    .info
                    .as_ref()
                    .and_then(|info| info.duration)
                    .map(|d| d as u64);
                if let Some(ref mut t) = self.tracks {
                    for tr in t.tracks.iter_mut() {
                        info.add_stream(track_to_stream(self.info.as_ref().unwrap(), tr));
                        tr.stream_index = info.streams.last().unwrap().index;
                    }
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            }
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + usize::from(size),
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            }
            e => {
                error!("{:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            debug!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets(self.tracks.as_ref().unwrap());
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {}
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                }
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(usize::from(size)))
                }
                e => {
                    error!("{:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1" => Some("av1".to_owned()),
        "V_VP8" => Some("vp8".to_owned()),
        "V_VP9" => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(video: &Video) -> Option<MediaKind> {
    let v = VideoInfo {
        width: video.pixel_width as usize,
        height: video.pixel_height as usize,
        // TODO parse Colour and/or CodecPrivate to extract the format
        format: None,
    };
    Some(MediaKind::Video(v))
}

fn track_entry_audio_kind(audio: &Audio) -> Option<MediaKind> {
    let rate = if let Some(r) = audio.output_sampling_frequency {
        r
    } else {
        audio.sampling_frequency
    };
    // TODO: complete it
    let map = if audio.channel_positions.is_none() {
        Some(ChannelMap::default_map(audio.channels as usize))
    } else {
        unimplemented!("Convert matroska map to rust-av map")
    };
    let a = AudioInfo {
        rate: rate as usize,
        map,
        format: None,
    };
    Some(MediaKind::Audio(a))
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => {
            if let Some(ref video) = t.video {
                track_entry_video_kind(video)
            } else {
                None
            }
        }
        0x2 => {
            if let Some(ref audio) = t.audio {
                track_entry_audio_kind(audio)
            } else {
                None
            }
        }
        _ => None,
    }
}

pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = t
        .track_timecode_scale
        .map(|ts| {
            if ts != 0. {
                (ts * info.timecode_scale as f64) as i64
            } else {
                info.timecode_scale as i64
            }
        })
        .unwrap_or(info.timecode_scale as i64);

    Stream {
        id: t.track_uid as isize,
        index: t.stream_index,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
        user_private: None,
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self, tracks: &Tracks) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                debug!("parsing simple block: {:?}", block);
                if let Some(index) = tracks.lookup(block.track_number) {
                    let packet = Packet {
                        data: i.into(),
                        t: TimeInfo {
                            pts: Some(i64::from(block.timecode)),
                            dts: None,
                            duration: None,
                            timebase: None,
                            user_private: None,
                        },
                        pos: None,
                        stream_index: index as isize,
                        is_key: block.keyframe,
                        is_corrupted: false,
                    };

                    v.push(Event::NewPacket(packet));
                }
            } else {
                error!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<dyn Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe(&self) -> &Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        ebml_header(&data[..100]).map(|_| 100).unwrap_or(0)
    }
}

pub const MKV_DESC: &dyn Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    },
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use std::io::Cursor;

    use log::info;
    use nom::Offset;

    use av_format::{buffer::*, demuxer::Context};

    use super::*;

    const webm: &[u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        info!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                info!("offset: {} bytes", webm.offset(i));
            }
            e => {
                info!("could not parse: {:?}", e);
            }
        }

        info!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => info!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => info!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(
            Box::new(MkvDemuxer::new()),
            Box::new(AccReader::new(Cursor::new(webm))),
        );
        info!("read headers: {:?}", context.read_headers().unwrap());
        info!("streams: {:?}", context.info.streams);
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_upper_case_globals)]

extern crate core_foundation;

use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};

pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID        = libc::uint32_t;

pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID;

pub type CGWindowListOption = libc::uint32_t;

pub const kCGWindowListOptionAll:              CGWindowListOption    = 0;
pub const kCGWindowListOptionOnScreenOnly:     CGWindowListOption    = 1 << 0;
pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1;
pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2;
pub const kCGWindowListOptionIncludingWindow:  CGWindowListOption    = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: CGWindowListOption    = 1 << 4;

pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent };
pub use core_foundation::array::{ CFArray, CFArrayRef };
pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex };
pub use core_foundation::base::{  CFIndex, CFRelease, CFTypeRef };

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

    // Window Services Reference
    pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;

}
<commit_msg>Add CGWindowList API<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_upper_case_globals)]

extern crate core_foundation;

use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};

use image::CGImageRef;

pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID        = libc::uint32_t;

pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID;

pub type CGWindowListOption = libc::uint32_t;

pub const kCGWindowListOptionAll:              CGWindowListOption    = 0;
pub const kCGWindowListOptionOnScreenOnly:     CGWindowListOption    = 1 << 0;
pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1;
pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2;
pub const kCGWindowListOptionIncludingWindow:  CGWindowListOption    = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: CGWindowListOption    = 1 << 4;

pub type CGWindowImageOption = libc::uint32_t;

pub const kCGWindowImageDefault: CGWindowImageOption = 0;
pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0;
pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1;
pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2;
pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3;
pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4;

pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent };
pub use core_foundation::array::{ CFArray, CFArrayRef };
pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex };
pub use core_foundation::base::{  CFIndex, CFRelease, CFTypeRef };

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub static CGRectNull: CGRect;
    pub static CGRectInfinite: CGRect;

    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

    // Window Services Reference
    pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;
    pub fn CGWindowListCreateImage(screenBounds: CGRect,
                                   listOptions: CGWindowListOption,
                                   windowId: CGWindowID,
                                   imageOptions: CGWindowImageOption) -> CGImageRef;

}
<|endoftext|>


<commit_before>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_id = "geoip#0.1"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *GeoIPRecord_);
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct GeoIPRecord_ {
    country_code: *c_char,
    country_code3: *c_char,
    country_name: *c_char,
    region: *c_char,
    city: *c_char,
    postal_code: *c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: uint,
    pub area_code: uint,
    pub charset: uint,
    pub continent_code: Option<String>,
    pub netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_code, false).as_str().unwrap()))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_code3, false).as_str().unwrap()))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_name, false).as_str().unwrap()))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.region, false).as_str().unwrap()))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.city, false).as_str().unwrap()))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.postal_code, false).as_str().unwrap()))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.continent_code, false).as_str().unwrap()))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                db: db
            })
        }
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<commit_msg>GeoIP can contain names that are not UTF-8<commit_after>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_id = "geoip#0.1"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *GeoIPRecord_);
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct GeoIPRecord_ {
    country_code: *c_char,
    country_code3: *c_char,
    country_name: *c_char,
    region: *c_char,
    city: *c_char,
    postal_code: *c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: uint,
    pub area_code: uint,
    pub charset: uint,
    pub continent_code: Option<String>,
    pub netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            CString::new(res.country_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            CString::new(res.country_code3, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            CString::new(res.country_name, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            CString::new(res.region, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            CString::new(res.city, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            CString::new(res.postal_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            CString::new(res.continent_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                db: db
            })
        }
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<|endoftext|>


<commit_before>//! Implementation of the fast sweeping method.
use super::min;

macro_rules! min_of {
    ( $d:ident, $s:expr, $i:expr, $ni:expr, $stride:expr ) => {
        if $i == 0 {
            $d[$s + $stride]
        } else if $i == $ni - 1 {
            $d[$s - $stride]
        } else {
            min($d[$s - $stride], $d[$s + $stride])
        };
    };
}

/// Computes the solution of the eikonal equation in 3D using the fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
///
/// `inv_dual_norm(d, [d1, d2, d3], [s1, s2, s3]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_anisotropic_dist_3d<F>(
    d: &mut [f64],
    dim: (usize, usize, usize),
    mut inv_dual_norm: F,
) where
    F: FnMut(f64, [f64; 3], [f64; 3]) -> f64,
{
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, d.len());
    let (sx, sy, sz) = (ny * nz, nz, 1);
    // sweep in 8 directions
    for m in 0..8 {
        for p in 1..nx {
            let (i, ip, isign) = if m & 0b001 == 0 {
                (nx - 1 - p, nx - 1 - p + 1, -1.)
            } else {
                (p, p - 1, 1.)
            };
            for q in 1..ny {
                let (j, jp, jsign) = if m & 0b010 == 0 {
                    (ny - 1 - q, ny - 1 - q + 1, -1.)
                } else {
                    (q, q - 1, 1.)
                };

                if m & 0b100 == 0 {
                    let ksign = -1.;
                    for k in (0..nz - 1).rev() {
                        let kp = k + 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                } else {
                    let ksign = 1.;
                    for k in 1..nz {
                        let kp = k - 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                }
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 3D using the Fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
pub fn fast_sweep_dist_3d(d: &mut [f64], dim: (usize, usize, usize)) {
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, d.len());
    let (sx, sy, sz) = (ny * nz, nz, 1);
    // sweep in 8 directions
    for m in 0..8 {
        for p in 0..nx {
            let i = if m & 0b001 == 0 { nx - 1 - p } else { p };
            for q in 0..ny {
                let j = if m & 0b010 == 0 { ny - 1 - q } else { q };
                for r in 0..nz {
                    let k = if m & 0b100 == 0 { nz - 1 - r } else { r };

                    let s = i * sx + j * sy + k * sz;

                    // get and order a, b, c
                    let (a, b, c) = {
                        use std::mem::swap;
                        let mut a = min_of!(d, s, i, nx, sx);
                        let mut b = min_of!(d, s, j, ny, sy);
                        let mut c = min_of!(d, s, k, nz, sz);

                        if a > b {
                            swap(&mut a, &mut b);
                        }
                        if b > c {
                            swap(&mut b, &mut c);
                        }
                        if a > b {
                            swap(&mut a, &mut b);
                        }

                        (a, b, c)
                    };

                    let x = if b >= a + 1. {
                        a + 1.
                    } else {
                        let x = 0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt());
                        if x <= c {
                            x
                        } else {
                            let v = (1. / 3.)
                                * (a + b
                                    + c
                                    + (3. + (a + b + c).powi(2) - 3. * (a * a + b * b + c * c))
                                        .sqrt());
                            v
                        }
                    };

                    d[s] = min(d[s], x);
                }
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the Fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
pub fn fast_sweep_dist_2d(d: &mut [f64], dim: (usize, usize)) {
    let (nx, ny) = dim;
    let (sx, sy) = (ny, 1);
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    for m in 0..4 {
        for p in 0..nx {
            let i = if m & 0b001 == 0 { nx - 1 - p } else { p };
            for q in 0..ny {
                let j = if m & 0b010 == 0 { ny - 1 - q } else { q };

                let s = i * sx + j * sy;
                let a = min_of!(d, s, i, nx, sx);
                let b = min_of!(d, s, j, ny, sy);

                let x = if (a - b).abs() >= 1. {
                    min(a, b) + 1.
                } else {
                    0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
                };

                d[s] = min(d[s], x);
            }
        }
    }
}

/// Fast sweeping method for a general anisotropic norm.
///
/// `inv_dual_norm(d, [d1, d2], [s1, s2]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_anisotropic_dist_2d<F>(d: &mut [f64], dim: (usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 2], [f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    let (sx, _sy) = (ny, 1);
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    // for m in 0..4 {
    //     for p in 1..nx {
    //         let (i, ip, isign) = if m & 0b001 == 0 {
    //             (nx - 1 - p, nx - 1 - p + 1, -1.)
    //         } else {
    //             (p, p - 1, 1.)
    //         };
    //         for q in 1..ny {
    //             let (j, jp, jsign) = if m & 0b010 == 0 {
    //                 (ny - 1 - q, ny - 1 - q + 1, -1.)
    //             } else {
    //                 (q, q - 1, 1.)
    //             };
    //
    //             let s = i * sx + j * sy;
    //
    //             d[s] = inv_dual_norm(
    //                 d[s],
    //                 [d[ip * sx + j * sy], d[i * sx + jp * sy]],
    //                 [isign, jsign],
    //             );
    //         }
    //     }
    // }

    // sweep in 4 directions
    // try to avoid bounds checks and impove cache locality (about 45% faster than the above version)
    for p in 1..nx {
        let (di, dj) = d.split_at_mut(p * sx);
        let di = &di[(p - 1) * sx..][..ny];
        let dj = &mut dj[..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [1., 1.]);
            // Rust 1.30 cannot optimize away 2 bounds checks here :(
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [1., -1.]);
        }
    }
    for p in (0..nx - 1).rev() {
        let (dj, di) = d.split_at_mut((p + 1) * sx);
        let di = &di[..ny];
        let dj = &mut dj[p * sx..][..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [-1., 1.]);
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [-1., -1.]);
        }
    }
}
<commit_msg>Remove legacy code<commit_after>//! Implementation of the fast sweeping method.

/// Computes the solution of the eikonal equation in 3D using the fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
///
/// `inv_dual_norm(d, [d1, d2, d3], [s1, s2, s3]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_anisotropic_dist_3d<F>(
    d: &mut [f64],
    dim: (usize, usize, usize),
    mut inv_dual_norm: F,
) where
    F: FnMut(f64, [f64; 3], [f64; 3]) -> f64,
{
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, d.len());
    let (sx, sy, sz) = (ny * nz, nz, 1);
    // sweep in 8 directions
    for m in 0..8 {
        for p in 1..nx {
            let (i, ip, isign) = if m & 0b001 == 0 {
                (nx - 1 - p, nx - 1 - p + 1, -1.)
            } else {
                (p, p - 1, 1.)
            };
            for q in 1..ny {
                let (j, jp, jsign) = if m & 0b010 == 0 {
                    (ny - 1 - q, ny - 1 - q + 1, -1.)
                } else {
                    (q, q - 1, 1.)
                };

                if m & 0b100 == 0 {
                    let ksign = -1.;
                    for k in (0..nz - 1).rev() {
                        let kp = k + 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                } else {
                    let ksign = 1.;
                    for k in 1..nz {
                        let kp = k - 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                }
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the fast sweeping algorithm.
///
/// `inv_dual_norm(d, [d1, d2], [s1, s2]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_anisotropic_dist_2d<F>(d: &mut [f64], dim: (usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 2], [f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    let (sx, _sy) = (ny, 1);
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    // for m in 0..4 {
    //     for p in 1..nx {
    //         let (i, ip, isign) = if m & 0b001 == 0 {
    //             (nx - 1 - p, nx - 1 - p + 1, -1.)
    //         } else {
    //             (p, p - 1, 1.)
    //         };
    //         for q in 1..ny {
    //             let (j, jp, jsign) = if m & 0b010 == 0 {
    //                 (ny - 1 - q, ny - 1 - q + 1, -1.)
    //             } else {
    //                 (q, q - 1, 1.)
    //             };
    //
    //             let s = i * sx + j * sy;
    //
    //             d[s] = inv_dual_norm(
    //                 d[s],
    //                 [d[ip * sx + j * sy], d[i * sx + jp * sy]],
    //                 [isign, jsign],
    //             );
    //         }
    //     }
    // }

    // sweep in 4 directions
    // try to avoid bounds checks and impove cache locality (about 45% faster than the above version)
    for p in 1..nx {
        let (di, dj) = d.split_at_mut(p * sx);
        let di = &di[(p - 1) * sx..][..ny];
        let dj = &mut dj[..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [1., 1.]);
            // Rust 1.30 cannot optimize away 2 bounds checks here :(
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [1., -1.]);
        }
    }
    for p in (0..nx - 1).rev() {
        let (dj, di) = d.split_at_mut((p + 1) * sx);
        let di = &di[..ny];
        let dj = &mut dj[p * sx..][..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [-1., 1.]);
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [-1., -1.]);
        }
    }
}
<|endoftext|>


<commit_before>//! Draw ellipse

pub use rectangle::centered;
pub use rectangle::centered_square as circle;

use internal;
use triangulation;
use Graphics;
use Color;
use math::Matrix2d;
use DrawState;

/// Ellipse border
#[derive(Copy, Clone)]
pub struct Border {
    /// The border color
    pub color: internal::Color,
    /// The border radius
    pub radius: internal::Radius,
}

/// An ellipse with filled color
#[derive(Copy, Clone)]
pub struct Ellipse {
    /// The ellipse color
    pub color: internal::Color,
    /// The ellipse border
    pub border: Option<Border>,
}

impl Ellipse {
    /// Creates a new ellipse
    pub fn new(color: internal::Color) -> Ellipse {
        Ellipse {
            color: color,
            border: None
        }
    }

    /// Creates a new ellipse border
    pub fn border(
        color: internal::Color,
        radius: internal::Radius
    ) -> Ellipse {
        Ellipse {
            color: [0.0; 4],
            border: Some(Border {
                    color: color,
                    radius: radius,
                })
        }
    }

    /// Draws the ellipse.
    pub fn draw<G>(
        &self,
        rectangle: internal::Rectangle,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        g.tri_list(
            draw_state,
            &self.color,
            |f|
        triangulation::with_ellipse_tri_list(
            128,
            transform,
            rectangle,
            |vertices| f(vertices)
        ));

        if let Some(Border { color, radius: border_radius }) = self.border {
            g.tri_list(
                &draw_state,
                &color,
                |f|
            triangulation::with_ellipse_border_tri_list(
                128,
                transform,
                rectangle,
                border_radius,
                |vertices| f(vertices)
            ));
        }
    }
}

/*
quack! {
    e: Ellipse[]
    get:
        fn () -> Color [] { Color(e.color) }
        fn () -> MaybeBorder [] { MaybeBorder(e.border) }
    set:
        fn (val: Color) [] { e.color = val.0 }
        fn (val: Border) [] { e.border = Some(val) }
        fn (val: MaybeBorder) [] { e.border = val.0 }
    action:
}
*/

#[cfg(test)]
mod test {
    use super::Ellipse;
    use super::Border;
    use Color;
    use quack::Set;

    #[test]
    fn test_ellipse() {
        let _ellipse = Ellipse::new([1.0; 4])
            .set(Color([0.0; 4]))
            .set(Border { color: [1.0; 4], radius: 3.0 });
    }
}
<commit_msg>Renamed `Ellipse::border` to `Ellipse::new_border`<commit_after>//! Draw ellipse

pub use rectangle::centered;
pub use rectangle::centered_square as circle;

use internal;
use triangulation;
use Graphics;
use Color;
use math::Matrix2d;
use DrawState;

/// Ellipse border
#[derive(Copy, Clone)]
pub struct Border {
    /// The border color
    pub color: internal::Color,
    /// The border radius
    pub radius: internal::Radius,
}

/// An ellipse with filled color
#[derive(Copy, Clone)]
pub struct Ellipse {
    /// The ellipse color
    pub color: internal::Color,
    /// The ellipse border
    pub border: Option<Border>,
}

impl Ellipse {
    /// Creates a new ellipse
    pub fn new(color: internal::Color) -> Ellipse {
        Ellipse {
            color: color,
            border: None
        }
    }

    /// Creates a new ellipse border
    pub fn new_border(
        color: internal::Color,
        radius: internal::Radius
    ) -> Ellipse {
        Ellipse {
            color: [0.0; 4],
            border: Some(Border {
                    color: color,
                    radius: radius,
                })
        }
    }

    /// Draws the ellipse.
    pub fn draw<G>(
        &self,
        rectangle: internal::Rectangle,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        g.tri_list(
            draw_state,
            &self.color,
            |f|
        triangulation::with_ellipse_tri_list(
            128,
            transform,
            rectangle,
            |vertices| f(vertices)
        ));

        if let Some(Border { color, radius: border_radius }) = self.border {
            g.tri_list(
                &draw_state,
                &color,
                |f|
            triangulation::with_ellipse_border_tri_list(
                128,
                transform,
                rectangle,
                border_radius,
                |vertices| f(vertices)
            ));
        }
    }
}

/*
quack! {
    e: Ellipse[]
    get:
        fn () -> Color [] { Color(e.color) }
        fn () -> MaybeBorder [] { MaybeBorder(e.border) }
    set:
        fn (val: Color) [] { e.color = val.0 }
        fn (val: Border) [] { e.border = Some(val) }
        fn (val: MaybeBorder) [] { e.border = val.0 }
    action:
}
*/

#[cfg(test)]
mod test {
    use super::Ellipse;
    use super::Border;
    use Color;
    use quack::Set;

    #[test]
    fn test_ellipse() {
        let _ellipse = Ellipse::new([1.0; 4])
            .set(Color([0.0; 4]))
            .set(Border { color: [1.0; 4], radius: 3.0 });
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use hyper::{
    service::{make_service_fn, service_fn},
    Body, Method, Response, Server, StatusCode,
};
use juniper::{
    tests::fixtures::starwars::{model::Database, schema::Query},
    EmptyMutation, EmptySubscription, RootNode,
};

#[tokio::main]
async fn main() {
    pretty_env_logger::init();

    let addr = ([127, 0, 0, 1], 3000).into();

    let db = Arc::new(Database::new());
    let root_node = Arc::new(RootNode::new(
        Query,
        EmptyMutation::<Database>::new(),
        EmptySubscription::<Database>::new(),
    ));

    let new_service = make_service_fn(move |_| {
        let root_node = root_node.clone();
        let ctx = db.clone();

        async move {
            Ok::<_, hyper::Error>(service_fn(move |req| {
                let root_node = root_node.clone();
                let ctx = ctx.clone();
                async move {
                    match (req.method(), req.uri().path()) {
                        (&Method::GET, "/") => juniper_hyper::graphiql("/graphql", None).await,
                        (&Method::GET, "/graphql") | (&Method::POST, "/graphql") => {
                            juniper_hyper::graphql(root_node, ctx, req).await
                        }
                        _ => {
                            let mut response = Response::new(Body::empty());
                            *response.status_mut() = StatusCode::NOT_FOUND;
                            Ok(response)
                        }
                    }
                }
            }))
        }
    });

    let server = Server::bind(&addr).serve(new_service);
    println!("Listening on http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e)
    }
}
<commit_msg>remove unnecessary moves (#740)<commit_after>use std::sync::Arc;

use hyper::{
    service::{make_service_fn, service_fn},
    Body, Method, Response, Server, StatusCode,
};
use juniper::{
    tests::fixtures::starwars::{model::Database, schema::Query},
    EmptyMutation, EmptySubscription, RootNode,
};

#[tokio::main]
async fn main() {
    pretty_env_logger::init();

    let addr = ([127, 0, 0, 1], 3000).into();

    let db = Arc::new(Database::new());
    let root_node = Arc::new(RootNode::new(
        Query,
        EmptyMutation::<Database>::new(),
        EmptySubscription::<Database>::new(),
    ));

    let new_service = make_service_fn(move |_| {
        let root_node = root_node.clone();
        let ctx = db.clone();

        async {
            Ok::<_, hyper::Error>(service_fn(move |req| {
                let root_node = root_node.clone();
                let ctx = ctx.clone();
                async {
                    match (req.method(), req.uri().path()) {
                        (&Method::GET, "/") => juniper_hyper::graphiql("/graphql", None).await,
                        (&Method::GET, "/graphql") | (&Method::POST, "/graphql") => {
                            juniper_hyper::graphql(root_node, ctx, req).await
                        }
                        _ => {
                            let mut response = Response::new(Body::empty());
                            *response.status_mut() = StatusCode::NOT_FOUND;
                            Ok(response)
                        }
                    }
                }
            }))
        }
    });

    let server = Server::bind(&addr).serve(new_service);
    println!("Listening on http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e)
    }
}
<|endoftext|>


<commit_before>//! # No-op OpenTelemetry Trace Implementation
//!
//! This implementation is returned as the global tracer if no `Tracer`
//! has been set. It is also useful for testing purposes as it is intended
//! to have minimal resource utilization and runtime impact.
use crate::{api, exporter};
use std::sync::Arc;
use std::time::SystemTime;

/// A no-op instance of a `Provider`.
#[derive(Debug)]
pub struct NoopProvider {}

impl api::Provider for NoopProvider {
    type Tracer = NoopTracer;

    /// Returns a new `NoopTracer` instance.
    fn get_tracer(&self, _name: &'static str) -> Self::Tracer {
        NoopTracer {}
    }
}

/// A no-op instance of a `Span`.
#[derive(Debug)]
pub struct NoopSpan {
    span_context: api::SpanContext,
}

impl Default for NoopSpan {
    fn default() -> Self {
        NoopSpan::new()
    }
}

impl NoopSpan {
    /// Creates a new `NoopSpan` instance.
    pub fn new() -> Self {
        NoopSpan {
            span_context: api::SpanContext::new(
                api::TraceId::invalid(),
                api::SpanId::invalid(),
                0,
                false,
            ),
        }
    }
}

impl api::Span for NoopSpan {
    /// Ignores all events
    fn add_event(&self, _name: String, _attributes: Vec<api::KeyValue>) {
        // Ignore
    }

    /// Ignores all events with timestamps
    fn add_event_with_timestamp(
        &self,
        _name: String,
        _timestamp: SystemTime,
        _attributes: Vec<api::KeyValue>,
    ) {
        // Ignored
    }

    /// Returns an invalid `SpanContext`.
    fn span_context(&self) -> api::SpanContext {
        self.span_context.clone()
    }

    /// Returns false, signifying that this span is never recording.
    fn is_recording(&self) -> bool {
        false
    }

    /// Ignores all attributes
    fn set_attribute(&self, _attribute: api::KeyValue) {
        // Ignored
    }

    /// Ignores status
    fn set_status(&self, _code: api::StatusCode, _message: String) {
        // Ignored
    }

    /// Ignores name updates
    fn update_name(&self, _new_name: String) {
        // Ignored
    }

    /// Ignores `Span` endings.
    fn end(&self) {
        // Ignored
    }
}

/// A no-op instance of a `Tracer`.
#[derive(Debug)]
pub struct NoopTracer {}

impl api::Tracer for NoopTracer {
    type Span = api::NoopSpan;

    /// Returns a `NoopSpan` as they are always invalid.
    fn invalid(&self) -> Self::Span {
        api::NoopSpan::new()
    }

    /// Starts a new `NoopSpan`.
    fn start_from_context(&self, _name: &str, _context: &api::Context) -> Self::Span {
        self.invalid()
    }

    /// Starts a SpanBuilder
    fn span_builder(&self, name: &str) -> api::SpanBuilder {
        api::SpanBuilder::from_name(name.to_string())
    }

    /// Builds a `NoopSpan` from a `SpanBuilder`
    fn build_with_context(&self, _builder: api::SpanBuilder, _cx: &api::Context) -> Self::Span {
        self.invalid()
    }
}

/// A no-op instance of an [`SpanExporter`].
///
/// [`SpanExporter`]: ../../../exporter/trace/trait.SpanExporter.html
#[derive(Debug)]
pub struct NoopSpanExporter {}

impl exporter::trace::SpanExporter for NoopSpanExporter {
    fn export(&self, _batch: Vec<Arc<exporter::trace::SpanData>>) -> exporter::trace::ExportResult {
        exporter::trace::ExportResult::Success
    }

    fn shutdown(&self) {
        // Noop
    }
}
<commit_msg>Propagate valid span context in noop tracer (#197)<commit_after>//! # No-op OpenTelemetry Trace Implementation
//!
//! This implementation is returned as the global tracer if no `Tracer`
//! has been set. It is also useful for testing purposes as it is intended
//! to have minimal resource utilization and runtime impact.
use crate::api::TraceContextExt;
use crate::{api, exporter};
use std::sync::Arc;
use std::time::SystemTime;

/// A no-op instance of a `Provider`.
#[derive(Debug)]
pub struct NoopProvider {}

impl api::Provider for NoopProvider {
    type Tracer = NoopTracer;

    /// Returns a new `NoopTracer` instance.
    fn get_tracer(&self, _name: &'static str) -> Self::Tracer {
        NoopTracer {}
    }
}

/// A no-op instance of a `Span`.
#[derive(Debug)]
pub struct NoopSpan {
    span_context: api::SpanContext,
}

impl Default for NoopSpan {
    fn default() -> Self {
        NoopSpan::new()
    }
}

impl NoopSpan {
    /// Creates a new `NoopSpan` instance.
    pub fn new() -> Self {
        NoopSpan {
            span_context: api::SpanContext::new(
                api::TraceId::invalid(),
                api::SpanId::invalid(),
                0,
                false,
            ),
        }
    }
}

impl api::Span for NoopSpan {
    /// Ignores all events
    fn add_event(&self, _name: String, _attributes: Vec<api::KeyValue>) {
        // Ignore
    }

    /// Ignores all events with timestamps
    fn add_event_with_timestamp(
        &self,
        _name: String,
        _timestamp: SystemTime,
        _attributes: Vec<api::KeyValue>,
    ) {
        // Ignored
    }

    /// Returns an invalid `SpanContext`.
    fn span_context(&self) -> api::SpanContext {
        self.span_context.clone()
    }

    /// Returns false, signifying that this span is never recording.
    fn is_recording(&self) -> bool {
        false
    }

    /// Ignores all attributes
    fn set_attribute(&self, _attribute: api::KeyValue) {
        // Ignored
    }

    /// Ignores status
    fn set_status(&self, _code: api::StatusCode, _message: String) {
        // Ignored
    }

    /// Ignores name updates
    fn update_name(&self, _new_name: String) {
        // Ignored
    }

    /// Ignores `Span` endings.
    fn end(&self) {
        // Ignored
    }
}

/// A no-op instance of a `Tracer`.
#[derive(Debug)]
pub struct NoopTracer {}

impl api::Tracer for NoopTracer {
    type Span = api::NoopSpan;

    /// Returns a `NoopSpan` as they are always invalid.
    fn invalid(&self) -> Self::Span {
        api::NoopSpan::new()
    }

    /// Starts a new `NoopSpan` in a given context.
    ///
    /// If the context contains a valid span context, it is progagated.
    fn start_from_context(&self, name: &str, cx: &api::Context) -> Self::Span {
        let builder = self.span_builder(name);
        self.build_with_context(builder, cx)
    }

    /// Starts a `SpanBuilder`.
    fn span_builder(&self, name: &str) -> api::SpanBuilder {
        api::SpanBuilder::from_name(name.to_string())
    }

    /// Builds a `NoopSpan` from a `SpanBuilder`.
    ///
    /// If the span builder or context contains a valid span context, it is progagated.
    fn build_with_context(&self, mut builder: api::SpanBuilder, cx: &api::Context) -> Self::Span {
        let parent_span_context = builder
            .parent_context
            .take()
            .or_else(|| Some(cx.span().span_context()).filter(|cx| cx.is_valid()))
            .or_else(|| cx.remote_span_context().cloned())
            .filter(|cx| cx.is_valid());
        if let Some(span_context) = parent_span_context {
            api::NoopSpan { span_context }
        } else {
            self.invalid()
        }
    }
}

/// A no-op instance of an [`SpanExporter`].
///
/// [`SpanExporter`]: ../../../exporter/trace/trait.SpanExporter.html
#[derive(Debug)]
pub struct NoopSpanExporter {}

impl exporter::trace::SpanExporter for NoopSpanExporter {
    fn export(&self, _batch: Vec<Arc<exporter::trace::SpanData>>) -> exporter::trace::ExportResult {
        exporter::trace::ExportResult::Success
    }

    fn shutdown(&self) {
        // Noop
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::api::{Span, Tracer};

    fn valid_span_context() -> api::SpanContext {
        api::SpanContext::new(
            api::TraceId::from_u128(42),
            api::SpanId::from_u64(42),
            0,
            true,
        )
    }

    #[test]
    fn noop_tracer_defaults_to_invalid_span() {
        let tracer = NoopTracer {};
        let span = tracer.start_from_context("foo", &api::Context::new());
        assert!(!span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_builder() {
        let tracer = NoopTracer {};
        let builder = tracer.span_builder("foo").with_parent(valid_span_context());
        let span = tracer.build_with_context(builder, &api::Context::new());
        assert!(span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_span() {
        let tracer = NoopTracer {};
        let cx = api::Context::new().with_span(NoopSpan {
            span_context: valid_span_context(),
        });
        let span = tracer.start_from_context("foo", &cx);
        assert!(span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_remote_span_context() {
        let tracer = NoopTracer {};
        let cx = api::Context::new().with_remote_span_context(valid_span_context());
        let span = tracer.start_from_context("foo", &cx);
        assert!(span.span_context().is_valid());
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

fn same_digits(a: u64, b: u64) -> bool {
    let astr = a.to_string();
    let bstr = b.to_string();

    if astr.len() != bstr.len() { return false }

    let aset : HashSet<char> = astr.chars().collect();
    let bset : HashSet<char> = bstr.chars().collect();

    aset == bset
 }

 pub fn main() {
    println!("{}", (1..).filter(|&n| [2*n,3*n,4*n,5*n,6*n].iter().all(|&m| same_digits(n,m))).nth(0).unwrap());
 }
<commit_msg>problem 52: reorder list of multiples<commit_after>use std::collections::HashSet;

fn same_digits(a: u64, b: u64) -> bool {
    let astr = a.to_string();
    let bstr = b.to_string();

    if astr.len() != bstr.len() { return false }

    let aset : HashSet<char> = astr.chars().collect();
    let bset : HashSet<char> = bstr.chars().collect();

    aset == bset
 }

 pub fn main() {
    println!("{}", (1..).filter(|&n| [6*n, 5*n, 4*n, 3*n, 2*n].iter().all(|&m| same_digits(n,m))).nth(0).unwrap());
 }
<|endoftext|>