<commit_before>#![feature(conservative_impl_trait)]

extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

type Id = u32;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (read_channel_out, read_channel_in) = mpsc::unbounded();
    let conn_id = Rc::new(RefCell::new(Counter::new()));

    let connections_inner = connections.clone();
    let conn_id_inner = conn_id.clone();
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections_inner = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            let channel = read_channel_out.clone();
            let handle_inner = handle.clone();
            let conn_id = conn_id_inner.clone();
            let f = upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let id = conn_id
                        .borrow_mut()
                        .next()
                        .expect("maximum amount of ids reached");
                    let (sink, stream) = framed.split();
                    let f = channel.send((id, stream));
                    spawn_future(f, "Senk stream to connection pool", &handle_inner);
                    connections_inner.write().unwrap().insert(id, sink);
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|_| ());

    let state_read = state.clone();
    let remote = core.remote();
    let read_handler = pool.spawn_fn(|| {
        read_channel_in.for_each(move |(id, stream)| {
            let state_read = state_read.clone();
            remote.spawn(move |_| {
                stream.for_each(move |msg| {
                                    handle_incoming(id, &msg, &mut state_read.write().unwrap());
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (write_channel_out, write_channel_in) = mpsc::unbounded();
    let connections_inner = connections.clone();
    let write_handler = pool.spawn_fn(move || {
        let connections = connections_inner.clone();
        write_channel_in.for_each(move |(id, state): (Id, Arc<RwLock<State>>)| {
                let connections = connections.clone();
                let mut connections = connections.write().unwrap();

                let sink = connections.remove(&id).expect("Tried to send to invalid client id");

                let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                println!("Sending message: {}", msg);
                let sink = sink.send(OwnedMessage::Text(msg))
                    .wait()
                    .expect("Error while sending to client");

                connections.insert(id, sink);
                Ok(())
            })
            .map_err(|_| ())
    });

    let remote = core.remote();
    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(write_channel_out, move |write_channel_out| {
            thread::sleep(Duration::from_millis(100));
            let connections = connections.clone();
            let state = state.clone();
            let write_channel_out_inner = write_channel_out.clone();
            remote.spawn(move |handle| {
                for (id, _) in connections.read().unwrap().iter() {
                    let f = write_channel_out_inner.clone().send((*id, state.clone()));
                    spawn_future(f, "Send message to client", handle);
                }
                Ok(())
            });

            // insert your terminating condition here
            match 1 {
                1 => Ok(Loop::Continue(write_channel_out)),
                2 => Ok(Loop::Break(())),
                _ => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(read_handler.select(write_handler)));
    core.run(handlers).map_err(|_| println!("Error while running core loop")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn handle_incoming(_:u32, msg: &OwnedMessage,  _: &mut State) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

struct Counter {
    count: Id,
}
impl Counter {
    fn new() -> Self {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

/*
impl Pos {
    fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }

    fn add_x(&mut self, x: i32) -> &mut Self {
        self.x += x;
        self
    }

    fn add_y(&mut self, y: i32) -> &mut Self {
        self.y += y;
        self
    }

    fn add(&mut self, x: i32, y: i32) -> &mut Self {
        self.x += x;
        self.y += y;
        self
    }
}
*/
<commit_msg>Core: Add comments, refactor tick into ue update<commit_after>#![feature(conservative_impl_trait)]

extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Remote, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

type Id = u32;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();

    let conn_id = Rc::new(RefCell::new(Counter::new()));
    let connections_inner = connections.clone();
    // Handle new connection
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections_inner = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            let channel = receive_channel_out.clone();
            let handle_inner = handle.clone();
            let conn_id = conn_id.clone();
            let f = upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let id = conn_id
                        .borrow_mut()
                        .next()
                        .expect("maximum amount of ids reached");
                    let (sink, stream) = framed.split();
                    let f = channel.send((id, stream));
                    spawn_future(f, "Senk stream to connection pool", &handle_inner);
                    connections_inner.write().unwrap().insert(id, sink);
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|_| ());

    // Handle receiving messages from a client
    let state_read = state.clone();
    let remote = core.remote();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let state_read = state_read.clone();
            remote.spawn(move |_| {
                stream.for_each(move |msg| {
                                    process_message(id, &msg, &mut state_read.write().unwrap());
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    // Handle sending messages to a client
    let connections_inner = connections.clone();
    let send_handler = pool.spawn_fn(move || {
        let connections = connections_inner.clone();
        send_channel_in.for_each(move |(id, state): (Id, Arc<RwLock<State>>)| {
                let connections = connections.clone();
                let mut connections = connections.write().unwrap();

                let sink = connections.remove(&id).expect("Tried to send to invalid client id");

                let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                println!("Sending message: {}", msg);
                let sink = sink.send(OwnedMessage::Text(msg))
                    .wait()
                    .expect("Error while sending to client");

                connections.insert(id, sink);
                Ok(())
            })
            .map_err(|_| ())
    });

    // Main 'logic' loop
    let remote = core.remote();
    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(send_channel_out, move |send_channel_out| {
            thread::sleep(Duration::from_millis(100));

            let should_continue = update(connections.clone(),
                                          state.clone(),
                                          send_channel_out.clone(),
                                          &remote);
            match should_continue {
                Ok(true) => Ok(Loop::Continue(send_channel_out)),
                Ok(false) => Ok(Loop::Break(())),
                Err(()) => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(receive_handler.select(send_handler)));
    core.run(handlers).map_err(|_| println!("Error while running core loop")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn process_message(_: u32, msg: &OwnedMessage, _: &mut State) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

type SinkContent =
    websocket::client::async::Framed<tokio_core::net::TcpStream,
                                     websocket::async::MessageCodec<websocket::OwnedMessage>>;
type SplitSink = futures::stream::SplitSink<SinkContent>;
// Represents one tick in the main loop
fn update(connections: Arc<RwLock<HashMap<Id, SplitSink>>>,
           state: Arc<RwLock<State>>,
           channel: futures::sync::mpsc::UnboundedSender<(Id, Arc<RwLock<State>>)>,
           remote: &Remote)
           -> Result<bool, ()> {
    remote.spawn(move |handle| {
        for (id, _) in connections.read().unwrap().iter() {
            let f = channel.clone().send((*id, state.clone()));
            spawn_future(f, "Send message to write handler", handle);
        }
        Ok(())
    });
    Ok(true)
}

struct Counter {
    count: Id,
}
impl Counter {
    fn new() -> Self {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

/*
impl Pos {
    fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }

    fn add_x(&mut self, x: i32) -> &mut Self {
        self.x += x;
        self
    }

    fn add_y(&mut self, y: i32) -> &mut Self {
        self.y += y;
        self
    }

    fn add(&mut self, x: i32, y: i32) -> &mut Self {
        self.x += x;
        self.y += y;
        self
    }
}
*/
<|endoftext|>


<commit_before><commit_msg>Add a function for partially escaping element text<commit_after><|endoftext|>


<commit_before><commit_msg>Shutdown event loop on empty slab.<commit_after><|endoftext|>


<commit_before><commit_msg>Add a test with \n in string<commit_after><|endoftext|>


<commit_before><commit_msg>Add note for myself<commit_after><|endoftext|>


<commit_before><commit_msg>Fix COM_BINLOG_DUMP_GTID serialization/deserialialization<commit_after><|endoftext|>


<commit_before><commit_msg>Add a samples_from_wave_bytes function<commit_after><|endoftext|>


<commit_before>use mio::*;
use mio::net::*;
use mio::unix::UnixReady;
use pool::Checkout;
use std::io::ErrorKind;
use network::buffer_queue::BufferQueue;
use network::{ClientResult,Protocol,Readiness};
use network::protocol::ProtocolResult;
use rustls::{ServerSession, Session};

pub enum TlsState {
  Initial,
  Handshake,
  Established,
  Error,
}

pub struct TlsHandshake {
  pub stream:    TcpStream,
  pub session:   ServerSession,
  pub readiness: Readiness,
}

impl TlsHandshake {
  pub fn new(session: ServerSession, stream: TcpStream) -> TlsHandshake {
    TlsHandshake {
      stream:   stream,
      session:   session,
      readiness: Readiness {
        front_interest:  UnixReady::from(Ready::readable()) | UnixReady::from(Ready::writable())
                           | UnixReady::hup() | UnixReady::error(),
        back_interest:   UnixReady::from(Ready::empty()),
        front_readiness: UnixReady::from(Ready::empty()),
        back_readiness:  UnixReady::from(Ready::empty()),
      },
    }
  }

  pub fn readable(&mut self) -> (ProtocolResult,ClientResult) {
    let mut can_read  = true;
    let mut can_write = true;

    loop {
      let mut can_work = false;

      if self.session.wants_read() && can_read {
        can_work = true;

        match self.session.read_tls(&mut self.stream) {
          Ok(_) => {},
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_read = false,
            _ => {
              error!("could not perform handshake: {:?}", e);
              return (ProtocolResult::Continue, ClientResult::CloseClient);
            }
          }
        }

        if let Err(e) = self.session.process_new_packets() {
          error!("could not perform handshake: {:?}", e);
          return (ProtocolResult::Continue, ClientResult::CloseClient);
        }
      }

      if self.session.wants_write() && can_write {
        can_work = true;

        match self.session.write_tls(&mut self.stream) {
          Ok(_) => {},
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            _ => {
              error!("could not perform handshake: {:?}", e);
              return (ProtocolResult::Continue, ClientResult::CloseClient);
            }
          }
        }

        if let Err(e) = self.session.process_new_packets() {
          error!("could not perform handshake: {:?}", e);
          return (ProtocolResult::Continue, ClientResult::CloseClient);
        }
      }

      if !can_work {
        break;
      }
    }

    if self.session.is_handshaking() {
      (ProtocolResult::Continue, ClientResult::Continue)
    } else {
      (ProtocolResult::Upgrade, ClientResult::Continue)
    }
  }
}

<commit_msg>do not request the front socket to be writable in rustls handshake<commit_after>use mio::*;
use mio::net::*;
use mio::unix::UnixReady;
use pool::Checkout;
use std::io::ErrorKind;
use network::buffer_queue::BufferQueue;
use network::{ClientResult,Protocol,Readiness};
use network::protocol::ProtocolResult;
use rustls::{ServerSession, Session};

pub enum TlsState {
  Initial,
  Handshake,
  Established,
  Error,
}

pub struct TlsHandshake {
  pub stream:    TcpStream,
  pub session:   ServerSession,
  pub readiness: Readiness,
}

impl TlsHandshake {
  pub fn new(session: ServerSession, stream: TcpStream) -> TlsHandshake {
    TlsHandshake {
      stream:   stream,
      session:   session,
      readiness: Readiness {
        front_interest:  UnixReady::from(Ready::readable())
                           | UnixReady::hup() | UnixReady::error(),
        back_interest:   UnixReady::from(Ready::empty()),
        front_readiness: UnixReady::from(Ready::empty()),
        back_readiness:  UnixReady::from(Ready::empty()),
      },
    }
  }

  pub fn readable(&mut self) -> (ProtocolResult,ClientResult) {
    let mut can_read  = true;
    let mut can_write = true;

    loop {
      let mut can_work = false;

      if self.session.wants_read() && can_read {
        can_work = true;

        match self.session.read_tls(&mut self.stream) {
          Ok(_) => {},
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_read = false,
            _ => {
              error!("could not perform handshake: {:?}", e);
              return (ProtocolResult::Continue, ClientResult::CloseClient);
            }
          }
        }

        if let Err(e) = self.session.process_new_packets() {
          error!("could not perform handshake: {:?}", e);
          return (ProtocolResult::Continue, ClientResult::CloseClient);
        }
      }

      if self.session.wants_write() && can_write {
        can_work = true;

        match self.session.write_tls(&mut self.stream) {
          Ok(_) => {},
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            _ => {
              error!("could not perform handshake: {:?}", e);
              return (ProtocolResult::Continue, ClientResult::CloseClient);
            }
          }
        }

        if let Err(e) = self.session.process_new_packets() {
          error!("could not perform handshake: {:?}", e);
          return (ProtocolResult::Continue, ClientResult::CloseClient);
        }
      }

      if !can_work {
        break;
      }
    }

    if self.session.is_handshaking() {
      (ProtocolResult::Continue, ClientResult::Continue)
    } else {
      (ProtocolResult::Upgrade, ClientResult::Continue)
    }
  }
}

<|endoftext|>


<commit_before>extern crate cbor;
extern crate quickcheck;
extern crate rand;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::fmt::Debug;
use rand::thread_rng;
use rustc_serialize::{Decodable, Encodable};
use quickcheck::{QuickCheck, StdGen, Testable};

use cbor::{Encoder, Decoder, Cbor, CborBytes, CborTagEncode};

fn qc_sized<A: Testable>(f: A, size: u64) {
    QuickCheck::new()
        .gen(StdGen::new(thread_rng(), size as usize))
        .tests(1_00)
        .max_tests(10_000)
        .quickcheck(f);
}

fn round_trip<T>(v: T) -> bool
        where T: Decodable + Encodable + Debug + PartialEq {
    let backv: T = decode(&encode(&v));
    assert_eq!(backv, v);
    true
}

fn encode<T: Encodable>(v: T) -> Vec<u8> {
    let mut enc = Encoder::from_memory();
    enc.encode(&[v]).unwrap();
    enc.as_bytes().to_vec()
}

fn decode<T: Decodable>(bytes: &[u8]) -> T {
    Decoder::from_bytes(bytes).decode().next().unwrap().unwrap()
}

#[allow(dead_code)]
fn readone(bytes: &[u8]) -> Cbor {
    Decoder::from_bytes(bytes).items().next().unwrap().unwrap()
}

macro_rules! round_trip_num {
    ($name:ident, $ty:ident) => (
        #[test]
        fn $name() {
            #![allow(trivial_numeric_casts)]
            fn prop(n: $ty) -> bool { round_trip(n) }
            qc_sized(prop as fn($ty) -> bool, ::std::$ty::MAX as u64)
        }
    );
}

round_trip_num!(roundtrip_prop_usize, usize);
round_trip_num!(roundtrip_prop_u64, u64);
round_trip_num!(roundtrip_prop_u32, u32);
round_trip_num!(roundtrip_prop_u16, u16);
round_trip_num!(roundtrip_prop_u8, u8);
round_trip_num!(roundtrip_prop_isize, isize);
round_trip_num!(roundtrip_prop_i64, i64);
round_trip_num!(roundtrip_prop_i32, i32);
round_trip_num!(roundtrip_prop_i16, i16);
round_trip_num!(roundtrip_prop_i8, i8);

#[test]
fn roundtrip_prop_f32() {
    fn prop(n: f32) -> bool { round_trip(n) }
    qc_sized(prop as fn(f32) -> bool, ::std::u64::MAX)
}

#[test]
fn roundtrip_prop_f64() {
    fn prop(n: f64) -> bool { round_trip(n) }
    qc_sized(prop as fn(f64) -> bool, ::std::u64::MAX)
}

#[test]
fn roundtrip_f32_min() {
    round_trip(::std::f32::MIN);
}

#[test]
fn roundtrip_f32_max() {
    round_trip(::std::f32::MAX);
}

#[test]
fn roundtrip_f64_min() {
    round_trip(::std::f64::MIN);
}

#[test]
fn roundtrip_f64_max() {
    round_trip(::std::f64::MAX);
}

macro_rules! round_trip_any {
    ($name:ident, $ty:ty) => (
        #[test]
        fn $name() {
            fn prop(n: $ty) -> bool { round_trip(n) }
            QuickCheck::new().quickcheck(prop as fn($ty) -> bool)
        }
    );
}

round_trip_any!(roundtrip_prop_nil, ());
round_trip_any!(roundtrip_prop_bool, bool);
round_trip_any!(roundtrip_prop_tuple, (i32, u32));
round_trip_any!(roundtrip_prop_tuple_in_tuple, (i32, (u32, i32), u32));
round_trip_any!(roundtrip_prop_vec, Vec<i32>);
round_trip_any!(roundtrip_prop_vec_in_vec, Vec<Vec<i32>>);
round_trip_any!(roundtrip_prop_map, HashMap<String, i32>);
round_trip_any!(roundtrip_prop_vec_in_map, HashMap<String, Vec<i32>>);
// round_trip_any!(roundtrip_prop_map_in_map,
                // HashMap<String, HashMap<String, i32>>);

#[test]
fn roundtrip_prop_byte_string() {
    fn prop(n: Vec<u8>) -> bool { round_trip(CborBytes(n)) }
    QuickCheck::new().quickcheck(prop as fn(Vec<u8>) -> bool)
}

#[test]
fn roundtrip_enum() {
    #[derive(Debug, PartialEq, RustcDecodable, RustcEncodable)]
    enum Color { Red, Blue(String, i32), Green { s: String, n: i32 } }

    round_trip(Color::Red);
    round_trip(Color::Blue("hi".to_string(), 5));
    round_trip(Color::Green { s: "hi".to_string(), n: 5 });
}

#[test]
fn roundtrip_struct() {
    #[derive(Debug, PartialEq, RustcDecodable, RustcEncodable)]
    struct Vowels { s: String, n: u32 }

    round_trip(Vowels { s: "cwm".to_string(), n: 1 });
}

#[test]
#[should_panic]
fn invalid_map_key() {
    let mut map = HashMap::new();
    map.insert(5, 5);
    encode(map);
}

#[test]
fn roundtrip_prop_tag() {
    use rustc_serialize::{Decoder, Encoder};

    #[derive(Debug, PartialEq)]
    struct MyTag {
        num: u64,
        data: Vec<i32>,
    }
    impl Decodable for MyTag {
        fn decode<D: Decoder>(d: &mut D) -> Result<MyTag, D::Error> {
            let tag = try!(d.read_u64());
            Ok(MyTag { num: tag, data: try!(Decodable::decode(d)) })
        }
    }
    impl Encodable for MyTag {
        fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
            CborTagEncode::new(self.num, &self.data).encode(e)
        }
    }
    fn prop(num: u64, data: Vec<i32>) -> bool {
        round_trip(MyTag { num: num, data: data })
    }
    QuickCheck::new().quickcheck(prop as fn(u64, Vec<i32>) -> bool)
}

#[test]
fn roundtrip_tag_fancier_data() {
    use rustc_serialize::{Decoder, Encoder};

    #[derive(Debug, PartialEq, RustcDecodable, RustcEncodable)]
    struct DataName(Vec<u8>);

    #[derive(Debug, PartialEq)]
    struct CustomData {
        name: DataName,
        value: Vec<u8>,
    }

    impl Decodable for CustomData {
        fn decode<D: Decoder>(d: &mut D) -> Result<CustomData, D::Error> {
            let _ = try!(d.read_u64());
            let (name, value) = try!(Decodable::decode(d));
            Ok(CustomData { name: name, value: value })
        }
    }
    impl Encodable for CustomData {
        fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
            CborTagEncode::new(100_000, &(&self.name, &self.value)).encode(e)
        }
    }
    assert!(round_trip(CustomData {
        name: DataName(b"hello".to_vec()),
        value: vec![1, 2, 3, 4, 5],
    }));
}

#[test]
fn test_oom() {
   let bad = vec![155u8, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF];
   let mut dec = Decoder::from_bytes(bad);
   assert!(dec.decode::<Vec<u32>>().next().is_none());
}

// #[test]
// fn test_oom_direct() {
   // let bad = vec![155u8, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF];
   // assert!(Vec::<u32>::decode(&mut DirectDecoder::from_bytes(bad)).is_err());
// }
<commit_msg>Test for encoding/decoding an RPC message.<commit_after>extern crate cbor;
extern crate quickcheck;
extern crate rand;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::fmt::Debug;
use rand::thread_rng;
use rustc_serialize::{Decodable, Encodable};
use quickcheck::{QuickCheck, StdGen, Testable};

use cbor::{Encoder, Decoder, Cbor, CborBytes, CborSigned, CborTagEncode};

fn qc_sized<A: Testable>(f: A, size: u64) {
    QuickCheck::new()
        .gen(StdGen::new(thread_rng(), size as usize))
        .tests(1_00)
        .max_tests(10_000)
        .quickcheck(f);
}

fn round_trip<T>(v: T) -> bool
        where T: Decodable + Encodable + Debug + PartialEq {
    let backv: T = decode(&encode(&v));
    assert_eq!(backv, v);
    true
}

fn encode<T: Encodable>(v: T) -> Vec<u8> {
    let mut enc = Encoder::from_memory();
    enc.encode(&[v]).unwrap();
    enc.as_bytes().to_vec()
}

fn decode<T: Decodable>(bytes: &[u8]) -> T {
    Decoder::from_bytes(bytes).decode().next().unwrap().unwrap()
}

#[allow(dead_code)]
fn readone(bytes: &[u8]) -> Cbor {
    Decoder::from_bytes(bytes).items().next().unwrap().unwrap()
}

macro_rules! round_trip_num {
    ($name:ident, $ty:ident) => (
        #[test]
        fn $name() {
            #![allow(trivial_numeric_casts)]
            fn prop(n: $ty) -> bool { round_trip(n) }
            qc_sized(prop as fn($ty) -> bool, ::std::$ty::MAX as u64)
        }
    );
}

round_trip_num!(roundtrip_prop_usize, usize);
round_trip_num!(roundtrip_prop_u64, u64);
round_trip_num!(roundtrip_prop_u32, u32);
round_trip_num!(roundtrip_prop_u16, u16);
round_trip_num!(roundtrip_prop_u8, u8);
round_trip_num!(roundtrip_prop_isize, isize);
round_trip_num!(roundtrip_prop_i64, i64);
round_trip_num!(roundtrip_prop_i32, i32);
round_trip_num!(roundtrip_prop_i16, i16);
round_trip_num!(roundtrip_prop_i8, i8);

#[test]
fn roundtrip_prop_f32() {
    fn prop(n: f32) -> bool { round_trip(n) }
    qc_sized(prop as fn(f32) -> bool, ::std::u64::MAX)
}

#[test]
fn roundtrip_prop_f64() {
    fn prop(n: f64) -> bool { round_trip(n) }
    qc_sized(prop as fn(f64) -> bool, ::std::u64::MAX)
}

#[test]
fn roundtrip_f32_min() {
    round_trip(::std::f32::MIN);
}

#[test]
fn roundtrip_f32_max() {
    round_trip(::std::f32::MAX);
}

#[test]
fn roundtrip_f64_min() {
    round_trip(::std::f64::MIN);
}

#[test]
fn roundtrip_f64_max() {
    round_trip(::std::f64::MAX);
}

macro_rules! round_trip_any {
    ($name:ident, $ty:ty) => (
        #[test]
        fn $name() {
            fn prop(n: $ty) -> bool { round_trip(n) }
            QuickCheck::new().quickcheck(prop as fn($ty) -> bool)
        }
    );
}

round_trip_any!(roundtrip_prop_nil, ());
round_trip_any!(roundtrip_prop_bool, bool);
round_trip_any!(roundtrip_prop_tuple, (i32, u32));
round_trip_any!(roundtrip_prop_tuple_in_tuple, (i32, (u32, i32), u32));
round_trip_any!(roundtrip_prop_vec, Vec<i32>);
round_trip_any!(roundtrip_prop_vec_in_vec, Vec<Vec<i32>>);
round_trip_any!(roundtrip_prop_map, HashMap<String, i32>);
round_trip_any!(roundtrip_prop_vec_in_map, HashMap<String, Vec<i32>>);
// round_trip_any!(roundtrip_prop_map_in_map,
                // HashMap<String, HashMap<String, i32>>);

#[test]
fn roundtrip_prop_byte_string() {
    fn prop(n: Vec<u8>) -> bool { round_trip(CborBytes(n)) }
    QuickCheck::new().quickcheck(prop as fn(Vec<u8>) -> bool)
}

#[test]
fn roundtrip_enum() {
    #[derive(Debug, PartialEq, RustcDecodable, RustcEncodable)]
    enum Color { Red, Blue(String, i32), Green { s: String, n: i32 } }

    round_trip(Color::Red);
    round_trip(Color::Blue("hi".to_string(), 5));
    round_trip(Color::Green { s: "hi".to_string(), n: 5 });
}

#[test]
fn roundtrip_struct() {
    #[derive(Debug, PartialEq, RustcDecodable, RustcEncodable)]
    struct Vowels { s: String, n: u32 }

    round_trip(Vowels { s: "cwm".to_string(), n: 1 });
}

#[test]
#[should_panic]
fn invalid_map_key() {
    let mut map = HashMap::new();
    map.insert(5, 5);
    encode(map);
}

#[test]
fn roundtrip_prop_tag() {
    use rustc_serialize::{Decoder, Encoder};

    #[derive(Debug, PartialEq)]
    struct MyTag {
        num: u64,
        data: Vec<i32>,
    }
    impl Decodable for MyTag {
        fn decode<D: Decoder>(d: &mut D) -> Result<MyTag, D::Error> {
            let tag = try!(d.read_u64());
            Ok(MyTag { num: tag, data: try!(Decodable::decode(d)) })
        }
    }
    impl Encodable for MyTag {
        fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
            CborTagEncode::new(self.num, &self.data).encode(e)
        }
    }
    fn prop(num: u64, data: Vec<i32>) -> bool {
        round_trip(MyTag { num: num, data: data })
    }
    QuickCheck::new().quickcheck(prop as fn(u64, Vec<i32>) -> bool)
}

#[test]
fn roundtrip_tag_fancier_data() {
    use rustc_serialize::{Decoder, Encoder};

    #[derive(Debug, PartialEq, RustcDecodable, RustcEncodable)]
    struct DataName(Vec<u8>);

    #[derive(Debug, PartialEq)]
    struct CustomData {
        name: DataName,
        value: Vec<u8>,
    }

    impl Decodable for CustomData {
        fn decode<D: Decoder>(d: &mut D) -> Result<CustomData, D::Error> {
            let _ = try!(d.read_u64());
            let (name, value) = try!(Decodable::decode(d));
            Ok(CustomData { name: name, value: value })
        }
    }
    impl Encodable for CustomData {
        fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
            CborTagEncode::new(100_000, &(&self.name, &self.value)).encode(e)
        }
    }
    assert!(round_trip(CustomData {
        name: DataName(b"hello".to_vec()),
        value: vec![1, 2, 3, 4, 5],
    }));
}

#[test]
fn rpc_decode() {
    #[derive(RustcDecodable, RustcEncodable)]
    struct Message {
        id: i64,
        method: String,
        params: CborBytes,
    }

    let send = encode(Message {
        id: 123,
        method: "foobar".to_owned(),
        params: CborBytes(encode(("val".to_owned(), true, -5,))),
    });
    let msg: Message = decode(&send);

    assert_eq!(msg.method, "foobar");
    let (val1, val2, val3): (String, bool, i32) = decode(&msg.params.0);
    assert_eq!(val1, "val");
    assert_eq!(val2, true);
    assert_eq!(val3, -5);
}

#[test]
fn test_oom() {
   let bad = vec![155u8, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF];
   let mut dec = Decoder::from_bytes(bad);
   assert!(dec.decode::<Vec<u32>>().next().is_none());
}

// #[test]
// fn test_oom_direct() {
   // let bad = vec![155u8, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF];
   // assert!(Vec::<u32>::decode(&mut DirectDecoder::from_bytes(bad)).is_err());
// }
<|endoftext|>


<commit_before>use super::names::ModNamesBuilder;
use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax};
use crate::repr::{
    ArgIx, BindingDirection, BindingFromRepr, BindingIx, BindingRepr, FuncIx, FuncRepr,
    ModuleFuncsRepr, ParamIx, ParamRepr, RetIx,
};
use crate::{AbiType, AtomType, Datatype, Location, Module, ValidationError};
use cranelift_entity::{EntityRef, PrimaryMap};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ops::Deref;

pub struct FunctionModuleBuilder<'a> {
    env: Module<'a>,
    names: &'a ModNamesBuilder,
    funcs: PrimaryMap<FuncIx, FuncRepr>,
}

impl<'a> FunctionModuleBuilder<'a> {
    pub fn new(env: Module<'a>, names: &'a ModNamesBuilder) -> Self {
        Self {
            env,
            names,
            funcs: PrimaryMap::new(),
        }
    }

    pub fn introduce_func(
        &mut self,
        name: &str,
        args: &[FuncArgSyntax],
        rets: &[FuncArgSyntax],
        bindings: &[BindingSyntax],
        location: Location,
    ) -> Result<(), ValidationError> {
        let mut validator = FuncValidator::new(location, &self.env);
        validator.introduce_args(args)?;
        validator.introduce_rets(rets)?;
        validator.introduce_bindings(bindings)?;

        let defined_ix = self.funcs.push(FuncRepr {
            args: validator.args,
            rets: validator.rets,
            bindings: validator.bindings,
        });
        let declared_ix = self.names.func_from_name(name).expect("declared func");
        assert_eq!(
            defined_ix, declared_ix,
            "funcs defined in different order than declared"
        );
        Ok(())
    }

    pub fn build(self) -> ModuleFuncsRepr {
        assert_eq!(
            self.names.funcs.len(),
            self.funcs.len(),
            "each func declared has been defined"
        );
        ModuleFuncsRepr {
            names: self.names.funcs.clone(),
            funcs: self.funcs,
        }
    }
}

struct FuncValidator<'a> {
    // arg name to declaration location and argument position
    param_names: HashMap<String, (Location, ParamIx)>,
    // Arg positions index into this vector:
    args: PrimaryMap<ArgIx, ParamRepr>,
    // Ret positions index into this vector:
    rets: PrimaryMap<RetIx, ParamRepr>,
    // binding name to
    binding_names: HashMap<&'a str, (Location, BindingIx)>,
    // param position to binding syntax
    bindings: PrimaryMap<BindingIx, BindingRepr>,
    param_binding_sites: HashMap<ParamIx, Location>,
    location: Location,
    module: &'a Module<'a>,
}

impl<'a> FuncValidator<'a> {
    fn new(location: Location, module: &'a Module<'a>) -> Self {
        Self {
            param_names: HashMap::new(),
            args: PrimaryMap::new(),
            rets: PrimaryMap::new(),
            binding_names: HashMap::new(),
            bindings: PrimaryMap::new(),
            param_binding_sites: HashMap::new(),
            location,
            module,
        }
    }
    fn introduce_param_name(
        &mut self,
        arg_syntax: &FuncArgSyntax,
        position: ParamIx,
    ) -> Result<ParamRepr, ValidationError> {
        if let Some((previous_location, _)) = self.param_names.get(arg_syntax.name) {
            Err(ValidationError::NameAlreadyExists {
                name: arg_syntax.name.to_owned(),
                at_location: arg_syntax.location,
                previous_location: *previous_location,
            })?;
        } else {
            self.param_names
                .insert(arg_syntax.name.to_owned(), (arg_syntax.location, position));
        }
        let type_ =
            AbiType::try_from(arg_syntax.type_.name).map_err(|_| ValidationError::Syntax {
                expected: "abi type",
                location: arg_syntax.type_.location,
            })?;
        Ok(ParamRepr {
            name: arg_syntax.name.to_owned(),
            type_,
        })
    }

    fn introduce_args(&mut self, args: &[FuncArgSyntax]) -> Result<(), ValidationError> {
        for (ix, arg) in args.iter().enumerate() {
            let arg_ix = ArgIx::new(ix);
            let a = self.introduce_param_name(arg, ParamIx::Arg(arg_ix))?;
            let pushed_arg_ix = self.args.push(a);
            assert_eq!(arg_ix, pushed_arg_ix);
        }
        Ok(())
    }
    fn introduce_rets(&mut self, rets: &[FuncArgSyntax]) -> Result<(), ValidationError> {
        if rets.len() > 1 {
            Err(ValidationError::Syntax {
                expected: "at most one return value",
                location: self.location,
            })?
        }
        for (ix, r) in rets.iter().enumerate() {
            let ret_ix = RetIx::new(ix);
            let r = self.introduce_param_name(r, ParamIx::Ret(ret_ix))?;
            let pushed_ret_ix = self.rets.push(r);
            assert_eq!(ret_ix, pushed_ret_ix);
        }
        Ok(())
    }

    fn introduce_bindings(
        &mut self,
        bindings: &[BindingSyntax<'a>],
    ) -> Result<(), ValidationError> {
        for (ix, binding) in bindings.iter().enumerate() {
            let ix = BindingIx::new(ix);
            let b = self.introduce_binding(binding, ix)?;
            let pushed_ix = self.bindings.push(b);
            assert_eq!(ix, pushed_ix);
        }
        for (ix, arg) in self.args.iter() {
            let position = ParamIx::Arg(ix);
            if !self.param_binding_sites.contains_key(&position) {
                self.bindings
                    .push(self.implicit_value_binding(&arg, position)?);
            }
        }
        for (ix, ret) in self.rets.iter() {
            let position = ParamIx::Ret(ix);
            if !self.param_binding_sites.contains_key(&position) {
                self.bindings
                    .push(self.implicit_value_binding(&ret, position)?);
            }
        }
        Ok(())
    }

    fn introduce_binding(
        &mut self,
        binding: &BindingSyntax<'a>,
        ix: BindingIx,
    ) -> Result<BindingRepr, ValidationError> {
        // 1. make sure binding name is unique
        if let Some((previous_location, _)) = self.binding_names.get(&binding.name) {
            Err(ValidationError::NameAlreadyExists {
                name: binding.name.to_owned(),
                at_location: binding.location,
                previous_location: *previous_location,
            })?;
        } else {
            self.binding_names
                .insert(binding.name, (binding.location, ix));
        }

        // 2. resolve type_ SyntaxIdent to a Datatype
        let type_ = self.module.datatype(&binding.type_.name).ok_or_else(|| {
            ValidationError::NameNotFound {
                name: binding.type_.name.to_owned(),
                use_location: binding.location,
            }
        })?;

        // 3. typecheck the binding:
        let from = self.validate_binding_ref(&binding, &type_)?;

        // 4. direction from syntax:
        let direction = match binding.direction {
            BindingDirSyntax::In => BindingDirection::In,
            BindingDirSyntax::InOut => BindingDirection::InOut,
            BindingDirSyntax::Out => BindingDirection::Out,
        };

        Ok(BindingRepr {
            name: binding.name.to_owned(),
            type_: type_.id(),
            direction,
            from,
        })
    }

    fn implicit_value_binding(
        &self,
        arg: &ParamRepr,
        position: ParamIx,
    ) -> Result<BindingRepr, ValidationError> {
        // 1. make sure binding name is unique. We're re-using the arg name
        // for the binding. If another binding overlapped with the arg name,
        // it is now at fault. (complicated, huh... :/)
        if let Some((previous_location, _)) = self.binding_names.get(arg.name.as_str()) {
            let (arg_location, _) = self.param_names.get(&arg.name).expect("arg introduced");
            Err(ValidationError::BindingNameAlreadyBound {
                name: arg.name.clone(),
                at_location: *previous_location,
                bound_location: *arg_location,
            })?;
        }

        // 2. resolve type
        let type_ = AtomType::from(arg.type_).datatype_id();

        // 3. no need to validate ref- we can construct it ourselves
        let from = BindingFromRepr::Value(position);

        // 4. direction depends on whether param is an arg or ret
        let direction = match position {
            ParamIx::Arg(_) => BindingDirection::In,
            ParamIx::Ret(_) => BindingDirection::Out,
        };

        Ok(BindingRepr {
            name: arg.name.clone(),
            type_,
            direction,
            from,
        })
    }

    fn get_arg(&self, arg_name: &str) -> Option<(ParamIx, ParamRepr)> {
        let (_, position) = self.param_names.get(arg_name)?;
        match position {
            ParamIx::Arg(ix) => Some((
                *position,
                self.args.get(*ix).expect("in-bounds arg index").clone(),
            )),
            ParamIx::Ret(ix) => Some((
                *position,
                self.rets.get(*ix).expect("in-bounds ret index").clone(),
            )),
        }
    }

    fn validate_binding_arg_mapping(
        &mut self,
        name: &str,
        location: Location,
    ) -> Result<(ParamIx, ParamRepr), ValidationError> {
        // Check that it refers to a valid arg:
        let (position, arg) = self.get_arg(name).ok_or_else(|| ValidationError::Syntax {
            expected: "name of an argument or return value",
            location,
        })?;
        // Check that the arg has only been used once:
        if let Some(use_location) = self.param_binding_sites.get(&position) {
            Err(ValidationError::BindingNameAlreadyBound {
                name: name.to_owned(),
                at_location: location,
                bound_location: *use_location,
            })?;
        } else {
            self.param_binding_sites.insert(position.clone(), location);
        }
        Ok((position, arg))
    }

    fn validate_binding_ref(
        &mut self,
        binding: &BindingSyntax,
        target_type: &Datatype<'a>,
    ) -> Result<BindingFromRepr, ValidationError> {
        match &binding.from {
            // A pointer to a name is accepted:
            BindingRefSyntax::Ptr(bref) => match bref.deref() {
                BindingRefSyntax::Name(ref name) => {
                    let (position, funcarg) =
                        self.validate_binding_arg_mapping(name, binding.location)?;
                    if funcarg.type_ != AbiType::I32 {
                        Err(ValidationError::BindingTypeError {
                            expected: "pointer bindings to be represented as an i32",
                            location: binding.location,
                        })?;
                    }
                    match position {
                        ParamIx::Arg(_) => {
                            // all good! Arg pointers are valid for in, inout, or out binding.
                        }
                        ParamIx::Ret(_) => {
                            Err(ValidationError::BindingTypeError {
                                expected: "return value cannot be bound to pointer",
                                location: binding.location,
                            })?;
                        }
                    }
                    Ok(BindingFromRepr::Ptr(position))
                }
                _ => Err(ValidationError::Syntax {
                    expected: "pointer binding must be of form *arg",
                    location: binding.location,
                }),
            },
            // A slice of two names is accepted:
            BindingRefSyntax::Slice(ref ptr_ref, ref len_ref) => {
                match (ptr_ref.deref(), len_ref.deref()) {
                    (
                        BindingRefSyntax::Name(ref ptr_name),
                        BindingRefSyntax::Name(ref len_name),
                    ) => {
                        let (ptr_position, ptr_arg) =
                            self.validate_binding_arg_mapping(ptr_name, binding.location)?;
                        if ptr_arg.type_ != AbiType::I32 {
                            Err(ValidationError::BindingTypeError {
                                expected: "slice pointer must be i32",
                                location: binding.location,
                            })?;
                        }
                        let (len_position, len_arg) =
                            self.validate_binding_arg_mapping(len_name, binding.location)?;
                        if len_arg.type_ != AbiType::I32 {
                            Err(ValidationError::BindingTypeError {
                                expected: "slice len must be i32",
                                location: binding.location,
                            })?;
                        }
                        match (&ptr_position, &len_position) {
                            (ParamIx::Arg(_), ParamIx::Arg(_)) => {}
                            _ => {
                                Err(ValidationError::BindingTypeError {
                                    expected: "slice bindings must be inputs",
                                    location: binding.location,
                                })?;
                            }
                        }
                        if binding.direction == BindingDirSyntax::Out {
                            Err(ValidationError::BindingTypeError {
                                expected: "slice bindings must be in or inout",
                                location: binding.location,
                            })?;
                        }
                        Ok(BindingFromRepr::Slice(ptr_position, len_position))
                    }
                    _ => Err(ValidationError::Syntax {
                        expected: "slice binding must be of form [ptr, len]",
                        location: binding.location,
                    }),
                }
            }
            // A bare name is accepted:
            BindingRefSyntax::Name(ref name) => {
                let (position, funcarg) =
                    self.validate_binding_arg_mapping(name, binding.location)?;

                // make sure funcarg.type_ is a valid representation of target type
                match target_type.abi_type() {
                    Some(target_repr) => {
                        if !funcarg.type_.can_represent(&target_repr) {
                            Err(ValidationError::BindingTypeError {
                                expected: "binding type which can represent argument type",
                                location: binding.location,
                            })?;
                        }
                    }
                    None => {
                        Err(ValidationError::BindingTypeError {
                            expected: "binding type to be representable as value (try passing by reference instead)",
                            location: binding.location,
                        })?;
                    }
                }
                // Arg values must be in-only bindings, Ret values must be out-only bindings
                match position {
                    ParamIx::Arg(_) => {
                        if binding.direction != BindingDirSyntax::In {
                            Err(ValidationError::BindingTypeError {
                                expected: "argument value must be input-only binding",
                                location: binding.location,
                            })?;
                        }
                    }
                    ParamIx::Ret(_) => {
                        if binding.direction != BindingDirSyntax::Out {
                            Err(ValidationError::BindingTypeError {
                                expected: "return value must be output-only binding",
                                location: binding.location,
                            })?;
                        }
                    }
                }
                Ok(BindingFromRepr::Value(position))
            }
        }
    }
}
<commit_msg>lucet-idl: func validator review comments<commit_after>use super::names::ModNamesBuilder;
use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax};
use crate::repr::{
    ArgIx, BindingDirection, BindingFromRepr, BindingIx, BindingRepr, FuncIx, FuncRepr,
    ModuleFuncsRepr, ParamIx, ParamRepr, RetIx,
};
use crate::{AbiType, AtomType, Datatype, Location, Module, ValidationError};
use cranelift_entity::{EntityRef, PrimaryMap};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ops::Deref;

pub struct FunctionModuleBuilder<'a> {
    env: Module<'a>,
    names: &'a ModNamesBuilder,
    funcs: PrimaryMap<FuncIx, FuncRepr>,
}

impl<'a> FunctionModuleBuilder<'a> {
    pub fn new(env: Module<'a>, names: &'a ModNamesBuilder) -> Self {
        Self {
            env,
            names,
            funcs: PrimaryMap::new(),
        }
    }

    pub fn introduce_func(
        &mut self,
        name: &str,
        args: &[FuncArgSyntax],
        rets: &[FuncArgSyntax],
        bindings: &[BindingSyntax],
        location: Location,
    ) -> Result<(), ValidationError> {
        let mut validator = FuncValidator::new(location, &self.env);
        validator.introduce_args(args)?;
        validator.introduce_rets(rets)?;
        validator.introduce_bindings(bindings)?;

        let defined_ix = self.funcs.push(FuncRepr {
            args: validator.args,
            rets: validator.rets,
            bindings: validator.bindings,
        });
        let declared_ix = self.names.func_from_name(name).expect("declared func");
        assert_eq!(
            defined_ix, declared_ix,
            "funcs defined in different order than declared"
        );
        Ok(())
    }

    pub fn build(self) -> ModuleFuncsRepr {
        assert_eq!(
            self.names.funcs.len(),
            self.funcs.len(),
            "each func declared has been defined"
        );
        ModuleFuncsRepr {
            names: self.names.funcs.clone(),
            funcs: self.funcs,
        }
    }
}

struct FuncValidator<'a> {
    // arg/return name to declaration location and argument position
    param_names: HashMap<String, (Location, ParamIx)>,
    // Arg positions index into this vector:
    args: PrimaryMap<ArgIx, ParamRepr>,
    // Ret positions index into this vector:
    rets: PrimaryMap<RetIx, ParamRepr>,
    // binding name to declaration location and binding position
    binding_names: HashMap<&'a str, (Location, BindingIx)>,
    // param position to binding syntax
    bindings: PrimaryMap<BindingIx, BindingRepr>,
    param_binding_sites: HashMap<ParamIx, Location>,
    location: Location,
    module: &'a Module<'a>,
}

impl<'a> FuncValidator<'a> {
    fn new(location: Location, module: &'a Module<'a>) -> Self {
        Self {
            param_names: HashMap::new(),
            args: PrimaryMap::new(),
            rets: PrimaryMap::new(),
            binding_names: HashMap::new(),
            bindings: PrimaryMap::new(),
            param_binding_sites: HashMap::new(),
            location,
            module,
        }
    }
    fn introduce_param_name(
        &mut self,
        arg_syntax: &FuncArgSyntax,
        position: ParamIx,
    ) -> Result<ParamRepr, ValidationError> {
        if let Some((previous_location, _)) = self.param_names.get(arg_syntax.name) {
            Err(ValidationError::NameAlreadyExists {
                name: arg_syntax.name.to_owned(),
                at_location: arg_syntax.location,
                previous_location: *previous_location,
            })?;
        } else {
            self.param_names
                .insert(arg_syntax.name.to_owned(), (arg_syntax.location, position));
        }
        let type_ =
            AbiType::try_from(arg_syntax.type_.name).map_err(|_| ValidationError::Syntax {
                expected: "abi type",
                location: arg_syntax.type_.location,
            })?;
        Ok(ParamRepr {
            name: arg_syntax.name.to_owned(),
            type_,
        })
    }

    fn introduce_args(&mut self, args: &[FuncArgSyntax]) -> Result<(), ValidationError> {
        for (ix, arg) in args.iter().enumerate() {
            let arg_ix = ArgIx::new(ix);
            let a = self.introduce_param_name(arg, ParamIx::Arg(arg_ix))?;
            let pushed_arg_ix = self.args.push(a);
            assert_eq!(arg_ix, pushed_arg_ix);
        }
        Ok(())
    }
    fn introduce_rets(&mut self, rets: &[FuncArgSyntax]) -> Result<(), ValidationError> {
        if rets.len() > 1 {
            Err(ValidationError::Syntax {
                expected: "at most one return value",
                location: self.location,
            })?
        }
        for (ix, r) in rets.iter().enumerate() {
            let ret_ix = RetIx::new(ix);
            let r = self.introduce_param_name(r, ParamIx::Ret(ret_ix))?;
            let pushed_ret_ix = self.rets.push(r);
            assert_eq!(ret_ix, pushed_ret_ix);
        }
        Ok(())
    }

    fn introduce_bindings(
        &mut self,
        bindings: &[BindingSyntax<'a>],
    ) -> Result<(), ValidationError> {
        for (ix, binding) in bindings.iter().enumerate() {
            let ix = BindingIx::new(ix);
            let b = self.introduce_binding(binding, ix)?;
            let pushed_ix = self.bindings.push(b);
            assert_eq!(ix, pushed_ix);
        }
        for (ix, arg) in self.args.iter() {
            let position = ParamIx::Arg(ix);
            if !self.param_binding_sites.contains_key(&position) {
                self.bindings
                    .push(self.implicit_value_binding(&arg, position)?);
            }
        }
        for (ix, ret) in self.rets.iter() {
            let position = ParamIx::Ret(ix);
            if !self.param_binding_sites.contains_key(&position) {
                self.bindings
                    .push(self.implicit_value_binding(&ret, position)?);
            }
        }
        Ok(())
    }

    fn introduce_binding(
        &mut self,
        binding: &BindingSyntax<'a>,
        ix: BindingIx,
    ) -> Result<BindingRepr, ValidationError> {
        // 1. make sure binding name is unique
        if let Some((previous_location, _)) = self.binding_names.get(&binding.name) {
            Err(ValidationError::NameAlreadyExists {
                name: binding.name.to_owned(),
                at_location: binding.location,
                previous_location: *previous_location,
            })?;
        } else {
            self.binding_names
                .insert(binding.name, (binding.location, ix));
        }

        // 2. resolve type_ SyntaxIdent to a Datatype
        let type_ = self.module.datatype(&binding.type_.name).ok_or_else(|| {
            ValidationError::NameNotFound {
                name: binding.type_.name.to_owned(),
                use_location: binding.location,
            }
        })?;

        // 3. typecheck the binding:
        let from = self.validate_binding_ref(&binding, &type_)?;

        // 4. direction from syntax:
        let direction = match binding.direction {
            BindingDirSyntax::In => BindingDirection::In,
            BindingDirSyntax::InOut => BindingDirection::InOut,
            BindingDirSyntax::Out => BindingDirection::Out,
        };

        Ok(BindingRepr {
            name: binding.name.to_owned(),
            type_: type_.id(),
            direction,
            from,
        })
    }

    fn implicit_value_binding(
        &self,
        arg: &ParamRepr,
        position: ParamIx,
    ) -> Result<BindingRepr, ValidationError> {
        // 1. make sure binding name is unique. We're re-using the arg name
        // for the binding. If another binding overlapped with the arg name,
        // it is now at fault. (complicated, huh... :/)
        if let Some((previous_location, _)) = self.binding_names.get(arg.name.as_str()) {
            let (arg_location, _) = self.param_names.get(&arg.name).expect("arg introduced");
            Err(ValidationError::BindingNameAlreadyBound {
                name: arg.name.clone(),
                at_location: *previous_location,
                bound_location: *arg_location,
            })?;
        }

        // 2. resolve type
        let type_ = AtomType::from(arg.type_).datatype_id();

        // 3. construct the binding from-value for this position
        let from = BindingFromRepr::Value(position);

        // 4. direction depends on whether param is an arg or ret
        let direction = match position {
            ParamIx::Arg(_) => BindingDirection::In,
            ParamIx::Ret(_) => BindingDirection::Out,
        };

        Ok(BindingRepr {
            name: arg.name.clone(),
            type_,
            direction,
            from,
        })
    }

    fn get_arg(&self, arg_name: &str) -> Option<(ParamIx, ParamRepr)> {
        let (_, position) = self.param_names.get(arg_name)?;
        match position {
            ParamIx::Arg(ix) => Some((
                *position,
                self.args.get(*ix).expect("in-bounds arg index").clone(),
            )),
            ParamIx::Ret(ix) => Some((
                *position,
                self.rets.get(*ix).expect("in-bounds ret index").clone(),
            )),
        }
    }

    fn validate_binding_arg_mapping(
        &mut self,
        name: &str,
        location: Location,
    ) -> Result<(ParamIx, ParamRepr), ValidationError> {
        // Check that it refers to a valid arg:
        let (position, arg) = self.get_arg(name).ok_or_else(|| ValidationError::Syntax {
            expected: "name of an argument or return value",
            location,
        })?;
        // Check that the arg has only been used once:
        if let Some(use_location) = self.param_binding_sites.get(&position) {
            Err(ValidationError::BindingNameAlreadyBound {
                name: name.to_owned(),
                at_location: location,
                bound_location: *use_location,
            })?;
        } else {
            self.param_binding_sites.insert(position.clone(), location);
        }
        Ok((position, arg))
    }

    fn validate_binding_ref(
        &mut self,
        binding: &BindingSyntax,
        target_type: &Datatype<'a>,
    ) -> Result<BindingFromRepr, ValidationError> {
        match &binding.from {
            // A pointer to a name is accepted:
            BindingRefSyntax::Ptr(bref) => match **bref {
                BindingRefSyntax::Name(ref name) => {
                    let (position, funcarg) =
                        self.validate_binding_arg_mapping(name, binding.location)?;
                    if funcarg.type_ != AbiType::I32 {
                        Err(ValidationError::BindingTypeError {
                            expected: "pointer bindings to be represented as an i32",
                            location: binding.location,
                        })?;
                    }
                    match position {
                        ParamIx::Arg(_) => {
                            // all good! Arg pointers are valid for in, inout, or out binding.
                        }
                        ParamIx::Ret(_) => {
                            Err(ValidationError::BindingTypeError {
                                expected: "return value cannot be bound to pointer",
                                location: binding.location,
                            })?;
                        }
                    }
                    Ok(BindingFromRepr::Ptr(position))
                }
                _ => Err(ValidationError::Syntax {
                    expected: "pointer binding must be of form *arg",
                    location: binding.location,
                }),
            },
            // A slice of two names is accepted:
            BindingRefSyntax::Slice(ref ptr_ref, ref len_ref) => {
                match (ptr_ref.deref(), len_ref.deref()) {
                    (
                        BindingRefSyntax::Name(ref ptr_name),
                        BindingRefSyntax::Name(ref len_name),
                    ) => {
                        let (ptr_position, ptr_arg) =
                            self.validate_binding_arg_mapping(ptr_name, binding.location)?;
                        if ptr_arg.type_ != AbiType::I32 {
                            Err(ValidationError::BindingTypeError {
                                expected: "slice pointer must be i32",
                                location: binding.location,
                            })?;
                        }
                        let (len_position, len_arg) =
                            self.validate_binding_arg_mapping(len_name, binding.location)?;
                        if len_arg.type_ != AbiType::I32 {
                            Err(ValidationError::BindingTypeError {
                                expected: "slice len must be i32",
                                location: binding.location,
                            })?;
                        }
                        match (&ptr_position, &len_position) {
                            (ParamIx::Arg(_), ParamIx::Arg(_)) => {}
                            _ => {
                                Err(ValidationError::BindingTypeError {
                                    expected: "slice bindings must be inputs",
                                    location: binding.location,
                                })?;
                            }
                        }
                        if binding.direction == BindingDirSyntax::Out {
                            Err(ValidationError::BindingTypeError {
                                expected: "slice bindings must be in or inout",
                                location: binding.location,
                            })?;
                        }
                        Ok(BindingFromRepr::Slice(ptr_position, len_position))
                    }
                    _ => Err(ValidationError::Syntax {
                        expected: "slice binding must be of form [ptr, len]",
                        location: binding.location,
                    }),
                }
            }
            // A bare name is accepted:
            BindingRefSyntax::Name(ref name) => {
                let (position, funcarg) =
                    self.validate_binding_arg_mapping(name, binding.location)?;

                // make sure funcarg.type_ is a valid representation of target type
                match target_type.abi_type() {
                    Some(target_repr) => {
                        if !funcarg.type_.can_represent(&target_repr) {
                            Err(ValidationError::BindingTypeError {
                                expected: "binding type which can represent argument type",
                                location: binding.location,
                            })?;
                        }
                    }
                    None => {
                        Err(ValidationError::BindingTypeError {
                            expected: "binding type to be representable as value (try passing by reference instead)",
                            location: binding.location,
                        })?;
                    }
                }
                // Arg values must be in-only bindings, Ret values must be out-only bindings
                match position {
                    ParamIx::Arg(_) => {
                        if binding.direction != BindingDirSyntax::In {
                            Err(ValidationError::BindingTypeError {
                                expected: "argument value must be input-only binding",
                                location: binding.location,
                            })?;
                        }
                    }
                    ParamIx::Ret(_) => {
                        if binding.direction != BindingDirSyntax::Out {
                            Err(ValidationError::BindingTypeError {
                                expected: "return value must be output-only binding",
                                location: binding.location,
                            })?;
                        }
                    }
                }
                Ok(BindingFromRepr::Value(position))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::ops::Deref;
use std::str;

use crate::crlf;

/// A custom small string.  The unsafe guts of this are in `NodeSmallString`
/// further down in this file.
#[derive(Clone, Default)]
pub(crate) struct NodeText(inner::NodeSmallString);

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText(inner::NodeSmallString::new())
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        NodeText(inner::NodeSmallString::from_str(string))
    }

    /// Inserts a `&str` at byte offset `byte_idx`.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        self.0.insert_str(byte_idx, string);
    }

    /// Inserts `string` at `byte_idx` and splits the resulting string in half,
    /// returning the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, byte_idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(byte_idx));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = byte_idx;
        let b = byte_idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        self.0.inline_if_possible();
        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        let len = self.len();
        self.0.insert_str(len, string);
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `byte_idx`.
    pub fn truncate(&mut self, byte_idx: usize) {
        self.0.truncate(byte_idx);
        self.0.inline_if_possible();
    }

    /// Drops the text before byte index `byte_idx`, shifting the
    /// rest of the text to fill in the space.
    pub fn truncate_front(&mut self, byte_idx: usize) {
        self.0.remove_range(0, byte_idx);
        self.0.inline_if_possible();
    }

    /// Removes the text in the byte index interval `[byte_start, byte_end)`.
    pub fn remove_range(&mut self, byte_start: usize, byte_end: usize) {
        self.0.remove_range(byte_start, byte_end);
        self.0.inline_if_possible();
    }

    /// Splits the `NodeText` at `byte_idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    pub fn split_off(&mut self, byte_idx: usize) -> Self {
        let other = NodeText(self.0.split_off(byte_idx));
        self.0.inline_if_possible();
        other
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

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

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

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

//=======================================================================

/// Takes two `NodeText`s and mends the CRLF break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is a single CRLF pair.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    let tot_len = l.len() + r.len();

    // Find the new split position, if any.
    let new_split_pos = {
        let l_split = crlf::prev_break(l.len(), l.as_bytes());
        let r_split = l.len() + crlf::next_break(0, r.as_bytes());
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The unsafe guts of NodeText, exposed through a safe API.
///
/// Try to keep this as small as possible, and implement functionality on
/// NodeText via the safe APIs whenever possible.
mod inner {
    use crate::tree::MAX_BYTES;
    use smallvec::{Array, SmallVec};
    use std::str;

    /// The backing internal buffer type for `NodeText`.
    #[derive(Copy, Clone)]
    struct BackingArray([u8; MAX_BYTES]);

    /// We need a very specific size of array, which is not necessarily
    /// supported directly by the impls in the smallvec crate.  We therefore
    /// have to implement this unsafe trait for our specific array size.
    /// TODO: once integer const generics land, and smallvec updates its APIs
    /// to use them, switch over and get rid of this unsafe impl.
    unsafe impl Array for BackingArray {
        type Item = u8;
        fn size() -> usize {
            MAX_BYTES
        }
    }

    /// Internal small string for `NodeText`.
    #[derive(Clone, Default)]
    pub struct NodeSmallString {
        buffer: SmallVec<BackingArray>,
    }

    impl NodeSmallString {
        #[inline(always)]
        pub fn new() -> Self {
            NodeSmallString {
                buffer: SmallVec::new(),
            }
        }

        #[inline(always)]
        pub fn with_capacity(capacity: usize) -> Self {
            NodeSmallString {
                buffer: SmallVec::with_capacity(capacity),
            }
        }

        #[inline(always)]
        pub fn from_str(string: &str) -> Self {
            let mut nodetext = NodeSmallString::with_capacity(string.len());
            nodetext.insert_str(0, string);
            nodetext
        }

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

        #[inline(always)]
        pub fn as_str(&self) -> &str {
            // NodeSmallString's methods don't allow `buffer` to become invalid
            // utf8, so this is safe.
            unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
        }

        /// Inserts `string` at `byte_idx`.
        ///
        /// Panics on out-of-bounds or of `byte_idx` isn't a char boundary.
        #[inline(always)]
        pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
            assert!(self.as_str().is_char_boundary(byte_idx));

            // Copy bytes from `string` into the appropriate space in the
            // buffer.
            self.buffer.insert_from_slice(byte_idx, string.as_bytes());
        }

        /// Removes text in range `[start_byte_idx, end_byte_idx)`
        ///
        /// Panics on out-of-bounds or non-char-boundary indices.
        #[inline(always)]
        pub fn remove_range(&mut self, start_byte_idx: usize, end_byte_idx: usize) {
            assert!(start_byte_idx <= end_byte_idx);
            assert!(end_byte_idx <= self.len());
            assert!(self.as_str().is_char_boundary(start_byte_idx));
            assert!(self.as_str().is_char_boundary(end_byte_idx));
            let len = self.len();
            let amt = end_byte_idx - start_byte_idx;

            self.buffer.copy_within(end_byte_idx..len, start_byte_idx);

            self.buffer.truncate(len - amt);
        }

        /// Removes text after `byte_idx`.
        #[inline(always)]
        pub fn truncate(&mut self, byte_idx: usize) {
            assert!(byte_idx <= self.len());
            assert!(self.as_str().is_char_boundary(byte_idx));
            self.buffer.truncate(byte_idx);
        }

        /// Splits at `byte_idx`, returning the right part and leaving the
        /// left part in the original.
        ///
        /// Panics on out-of-bounds or of `byte_idx` isn't a char boundary.
        #[inline(always)]
        pub fn split_off(&mut self, byte_idx: usize) -> Self {
            assert!(byte_idx <= self.len());
            assert!(self.as_str().is_char_boundary(byte_idx));
            let len = self.len();
            let mut other = NodeSmallString::with_capacity(len - byte_idx);
            other.buffer.extend_from_slice(&self.buffer[byte_idx..]);
            self.buffer.truncate(byte_idx);
            other
        }

        /// Re-inlines the data if it's been heap allocated but can
        /// fit inline.
        #[inline(always)]
        pub fn inline_if_possible(&mut self) {
            if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
                self.buffer.shrink_to_fit();
            }
        }
    }

    //-----------------------------------------------------------------------

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

        #[test]
        fn small_string_basics() {
            let s = NodeSmallString::from_str("Hello!");
            assert_eq!("Hello!", s.as_str());
            assert_eq!(6, s.len());
        }

        #[test]
        fn insert_str_01() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.insert_str(3, "oz");
            assert_eq!("Helozlo!", s.as_str());
        }

        #[test]
        #[should_panic]
        fn insert_str_02() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.insert_str(7, "oz");
        }

        #[test]
        #[should_panic]
        fn insert_str_03() {
            let mut s = NodeSmallString::from_str("こんにちは");
            s.insert_str(4, "oz");
        }

        #[test]
        fn remove_range_01() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.remove_range(2, 4);
            assert_eq!("Heo!", s.as_str());
        }

        #[test]
        #[should_panic]
        fn remove_range_02() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.remove_range(4, 2);
        }

        #[test]
        #[should_panic]
        fn remove_range_03() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.remove_range(2, 7);
        }

        #[test]
        #[should_panic]
        fn remove_range_04() {
            let mut s = NodeSmallString::from_str("こんにちは");
            s.remove_range(2, 4);
        }

        #[test]
        fn truncate_01() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.truncate(4);
            assert_eq!("Hell", s.as_str());
        }

        #[test]
        #[should_panic]
        fn truncate_02() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.truncate(7);
        }

        #[test]
        #[should_panic]
        fn truncate_03() {
            let mut s = NodeSmallString::from_str("こんにちは");
            s.truncate(4);
        }

        #[test]
        fn split_off_01() {
            let mut s1 = NodeSmallString::from_str("Hello!");
            let s2 = s1.split_off(4);
            assert_eq!("Hell", s1.as_str());
            assert_eq!("o!", s2.as_str());
        }

        #[test]
        #[should_panic]
        fn split_off_02() {
            let mut s1 = NodeSmallString::from_str("Hello!");
            s1.split_off(7);
        }

        #[test]
        #[should_panic]
        fn split_off_03() {
            let mut s1 = NodeSmallString::from_str("こんにちは");
            s1.split_off(4);
        }
    }
}
<commit_msg>Some asserts can be debug_asserts since they're enforced by stdlib<commit_after>use std::borrow::Borrow;
use std::ops::Deref;
use std::str;

use crate::crlf;

/// A custom small string.  The unsafe guts of this are in `NodeSmallString`
/// further down in this file.
#[derive(Clone, Default)]
pub(crate) struct NodeText(inner::NodeSmallString);

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText(inner::NodeSmallString::new())
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        NodeText(inner::NodeSmallString::from_str(string))
    }

    /// Inserts a `&str` at byte offset `byte_idx`.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        self.0.insert_str(byte_idx, string);
    }

    /// Inserts `string` at `byte_idx` and splits the resulting string in half,
    /// returning the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, byte_idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(byte_idx));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = byte_idx;
        let b = byte_idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        self.0.inline_if_possible();
        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        let len = self.len();
        self.0.insert_str(len, string);
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `byte_idx`.
    pub fn truncate(&mut self, byte_idx: usize) {
        self.0.truncate(byte_idx);
        self.0.inline_if_possible();
    }

    /// Drops the text before byte index `byte_idx`, shifting the
    /// rest of the text to fill in the space.
    pub fn truncate_front(&mut self, byte_idx: usize) {
        self.0.remove_range(0, byte_idx);
        self.0.inline_if_possible();
    }

    /// Removes the text in the byte index interval `[byte_start, byte_end)`.
    pub fn remove_range(&mut self, byte_start: usize, byte_end: usize) {
        self.0.remove_range(byte_start, byte_end);
        self.0.inline_if_possible();
    }

    /// Splits the `NodeText` at `byte_idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    pub fn split_off(&mut self, byte_idx: usize) -> Self {
        let other = NodeText(self.0.split_off(byte_idx));
        self.0.inline_if_possible();
        other
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

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

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

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

//=======================================================================

/// Takes two `NodeText`s and mends the CRLF break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is a single CRLF pair.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    let tot_len = l.len() + r.len();

    // Find the new split position, if any.
    let new_split_pos = {
        let l_split = crlf::prev_break(l.len(), l.as_bytes());
        let r_split = l.len() + crlf::next_break(0, r.as_bytes());
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The unsafe guts of NodeText, exposed through a safe API.
///
/// Try to keep this as small as possible, and implement functionality on
/// NodeText via the safe APIs whenever possible.
mod inner {
    use crate::tree::MAX_BYTES;
    use smallvec::{Array, SmallVec};
    use std::str;

    /// The backing internal buffer type for `NodeText`.
    #[derive(Copy, Clone)]
    struct BackingArray([u8; MAX_BYTES]);

    /// We need a very specific size of array, which is not necessarily
    /// supported directly by the impls in the smallvec crate.  We therefore
    /// have to implement this unsafe trait for our specific array size.
    /// TODO: once integer const generics land, and smallvec updates its APIs
    /// to use them, switch over and get rid of this unsafe impl.
    unsafe impl Array for BackingArray {
        type Item = u8;
        fn size() -> usize {
            MAX_BYTES
        }
    }

    /// Internal small string for `NodeText`.
    #[derive(Clone, Default)]
    pub struct NodeSmallString {
        buffer: SmallVec<BackingArray>,
    }

    impl NodeSmallString {
        #[inline(always)]
        pub fn new() -> Self {
            NodeSmallString {
                buffer: SmallVec::new(),
            }
        }

        #[inline(always)]
        pub fn with_capacity(capacity: usize) -> Self {
            NodeSmallString {
                buffer: SmallVec::with_capacity(capacity),
            }
        }

        #[inline(always)]
        pub fn from_str(string: &str) -> Self {
            let mut nodetext = NodeSmallString::with_capacity(string.len());
            nodetext.insert_str(0, string);
            nodetext
        }

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

        #[inline(always)]
        pub fn as_str(&self) -> &str {
            // NodeSmallString's methods don't allow `buffer` to become invalid
            // utf8, so this is safe.
            unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
        }

        /// Inserts `string` at `byte_idx`.
        ///
        /// Panics on out-of-bounds or of `byte_idx` isn't a char boundary.
        #[inline(always)]
        pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
            assert!(self.as_str().is_char_boundary(byte_idx));

            // Copy bytes from `string` into the appropriate space in the
            // buffer.
            self.buffer.insert_from_slice(byte_idx, string.as_bytes());
        }

        /// Removes text in range `[start_byte_idx, end_byte_idx)`
        ///
        /// Panics on out-of-bounds or non-char-boundary indices.
        #[inline(always)]
        pub fn remove_range(&mut self, start_byte_idx: usize, end_byte_idx: usize) {
            assert!(start_byte_idx <= end_byte_idx);
            // Already checked by copy_within/is_char_boundary.
            debug_assert!(end_byte_idx <= self.len());
            assert!(self.as_str().is_char_boundary(start_byte_idx));
            assert!(self.as_str().is_char_boundary(end_byte_idx));
            let len = self.len();
            let amt = end_byte_idx - start_byte_idx;

            self.buffer.copy_within(end_byte_idx..len, start_byte_idx);

            self.buffer.truncate(len - amt);
        }

        /// Removes text after `byte_idx`.
        #[inline(always)]
        pub fn truncate(&mut self, byte_idx: usize) {
            // Already checked by is_char_boundary.
            debug_assert!(byte_idx <= self.len());
            assert!(self.as_str().is_char_boundary(byte_idx));
            self.buffer.truncate(byte_idx);
        }

        /// Splits at `byte_idx`, returning the right part and leaving the
        /// left part in the original.
        ///
        /// Panics on out-of-bounds or of `byte_idx` isn't a char boundary.
        #[inline(always)]
        pub fn split_off(&mut self, byte_idx: usize) -> Self {
            // Already checked by is_char_boundary.
            debug_assert!(byte_idx <= self.len());
            assert!(self.as_str().is_char_boundary(byte_idx));
            let len = self.len();
            let mut other = NodeSmallString::with_capacity(len - byte_idx);
            other.buffer.extend_from_slice(&self.buffer[byte_idx..]);
            self.buffer.truncate(byte_idx);
            other
        }

        /// Re-inlines the data if it's been heap allocated but can
        /// fit inline.
        #[inline(always)]
        pub fn inline_if_possible(&mut self) {
            if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
                self.buffer.shrink_to_fit();
            }
        }
    }

    //-----------------------------------------------------------------------

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

        #[test]
        fn small_string_basics() {
            let s = NodeSmallString::from_str("Hello!");
            assert_eq!("Hello!", s.as_str());
            assert_eq!(6, s.len());
        }

        #[test]
        fn insert_str_01() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.insert_str(3, "oz");
            assert_eq!("Helozlo!", s.as_str());
        }

        #[test]
        #[should_panic]
        fn insert_str_02() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.insert_str(7, "oz");
        }

        #[test]
        #[should_panic]
        fn insert_str_03() {
            let mut s = NodeSmallString::from_str("こんにちは");
            s.insert_str(4, "oz");
        }

        #[test]
        fn remove_range_01() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.remove_range(2, 4);
            assert_eq!("Heo!", s.as_str());
        }

        #[test]
        #[should_panic]
        fn remove_range_02() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.remove_range(4, 2);
        }

        #[test]
        #[should_panic]
        fn remove_range_03() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.remove_range(2, 7);
        }

        #[test]
        #[should_panic]
        fn remove_range_04() {
            let mut s = NodeSmallString::from_str("こんにちは");
            s.remove_range(2, 4);
        }

        #[test]
        fn truncate_01() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.truncate(4);
            assert_eq!("Hell", s.as_str());
        }

        #[test]
        #[should_panic]
        fn truncate_02() {
            let mut s = NodeSmallString::from_str("Hello!");
            s.truncate(7);
        }

        #[test]
        #[should_panic]
        fn truncate_03() {
            let mut s = NodeSmallString::from_str("こんにちは");
            s.truncate(4);
        }

        #[test]
        fn split_off_01() {
            let mut s1 = NodeSmallString::from_str("Hello!");
            let s2 = s1.split_off(4);
            assert_eq!("Hell", s1.as_str());
            assert_eq!("o!", s2.as_str());
        }

        #[test]
        #[should_panic]
        fn split_off_02() {
            let mut s1 = NodeSmallString::from_str("Hello!");
            s1.split_off(7);
        }

        #[test]
        #[should_panic]
        fn split_off_03() {
            let mut s1 = NodeSmallString::from_str("こんにちは");
            s1.split_off(4);
        }
    }
}
<|endoftext|>