<commit_before>extern crate blurz;

static BATTERY_SERVICE_UUID: &'static str = "0000180f-0000-1000-8000-00805f9b34fb";
static COLOR_PICKER_SERVICE_UUID: &'static str = "00001812-0000-1000-8000-00805f9b34fb";

use std::error::Error;
use std::time::Duration;
use std::thread;

use blurz::bluetooth_adapter::BluetoothAdapter as Adapter;
use blurz::bluetooth_device::BluetoothDevice as Device;
use blurz::bluetooth_gatt_service::BluetoothGATTService as Service;
use blurz::bluetooth_gatt_characteristic::BluetoothGATTCharacteristic as Characteristic;
use blurz::bluetooth_gatt_descriptor::BluetoothGATTDescriptor as Descriptor;
use blurz::bluetooth_discovery_session::BluetoothDiscoverySession as DiscoverySession;

fn test2() -> Result<(), Box<Error>> {
    let adapter: Adapter = try!(Adapter::init());
    let session = try!(DiscoverySession::create_session(adapter.get_id()));
    try!(session.start_discovery());
    //let mut devices = vec!();
    for _ in 0..5 {
        let devices = try!(adapter.get_device_list());
        if !devices.is_empty() {
            break;
        }
        thread::sleep(Duration::from_millis(1000));
    }
    try!(session.stop_discovery());
    let devices = try!(adapter.get_device_list());
    if devices.is_empty() {
        return Err(Box::from("No device found"));
    }
    println!("{} device(s) found", devices.len());
    let mut device: Device = Device::new("".to_string());
    'device_loop: for d in devices {
        device = Device::new(d.clone());
        println!("{} {:?}", device.get_id(), device.get_alias());
        let uuids = try!(device.get_uuids());
        println!("{:?}", uuids);
        'uuid_loop: for uuid in uuids {
            if uuid == COLOR_PICKER_SERVICE_UUID ||
               uuid == BATTERY_SERVICE_UUID {
                println!("{:?} has a service!", device.get_alias());
                println!("connect device...");
                device.connect().ok();
                if try!(device.is_connected()) {
                    println!("checking gatt...");
                    // We need to wait a bit after calling connect to safely
                    // get the gatt services
                    thread::sleep(Duration::from_millis(5000));
                    match device.get_gatt_services() {
                        Ok(_) => break 'device_loop,
                        Err(e) => println!("{:?}", e),
                    }
                } else {
                    println!("could not connect");
                }
            }
        }
        println!("");
    }
    adapter.stop_discovery().ok();
    if !try!(device.is_connected()) {
        return Err(Box::from("No connectable device found"));
    }
    let services = try!(device.get_gatt_services());
    for service in services {
        let s = Service::new(service.clone());
        println!("{:?}", s);
        let characteristics = try!(s.get_gatt_characteristics());
        for characteristic in characteristics {
            let c = Characteristic::new(characteristic.clone());
            println!("{:?}", c);
            println!("Value: {:?}", c.read_value());
            let descriptors = try!(c.get_gatt_descriptors());
            for descriptor in descriptors {
                let d = Descriptor::new(descriptor.clone());
                println!("{:?}", d);
                println!("Value: {:?}", d.read_value());
            }

        }
    }
    try!(device.disconnect());
    Ok(())
}

fn main() {
    match test2() {
         Ok(_) => (),
         Err(e) => println!("{:?}", e),
     }
}
<commit_msg>Update test2<commit_after>extern crate blurz;

static BATTERY_SERVICE_UUID: &'static str = "0000180f-0000-1000-8000-00805f9b34fb";
static COLOR_PICKER_SERVICE_UUID: &'static str = "00001812-0000-1000-8000-00805f9b34fb";

use std::error::Error;
use std::time::Duration;
use std::thread;

use blurz::bluetooth_adapter::BluetoothAdapter as Adapter;
use blurz::bluetooth_device::BluetoothDevice as Device;
use blurz::bluetooth_gatt_service::BluetoothGATTService as Service;
use blurz::bluetooth_gatt_characteristic::BluetoothGATTCharacteristic as Characteristic;
use blurz::bluetooth_gatt_descriptor::BluetoothGATTDescriptor as Descriptor;
use blurz::bluetooth_discovery_session::BluetoothDiscoverySession as DiscoverySession;

fn test2() -> Result<(), Box<Error>> {
    let adapter: Adapter = try!(Adapter::init());
    let session = try!(DiscoverySession::create_session(adapter.get_id()));
    try!(session.start_discovery());
    //let mut devices = vec!();
    for _ in 0..5 {
        let devices = try!(adapter.get_device_list());
        if !devices.is_empty() {
            break;
        }
        thread::sleep(Duration::from_millis(1000));
    }
    try!(session.stop_discovery());
    let devices = try!(adapter.get_device_list());
    if devices.is_empty() {
        return Err(Box::from("No device found"));
    }
    println!("{} device(s) found", devices.len());
    let mut device: Device = Device::new("".to_string());
    'device_loop: for d in devices {
        device = Device::new(d.clone());
        println!("{} {:?}", device.get_id(), device.get_alias());
        let uuids = try!(device.get_uuids());
        println!("{:?}", uuids);
        'uuid_loop: for uuid in uuids {
            if uuid == COLOR_PICKER_SERVICE_UUID ||
               uuid == BATTERY_SERVICE_UUID {
                println!("{:?} has a service!", device.get_alias());
                println!("connect device...");
                device.connect().ok();
                if try!(device.is_connected()) {
                    println!("checking gatt...");
                    // We need to wait a bit after calling connect to safely
                    // get the gatt services
                    thread::sleep(Duration::from_millis(5000));
                    match device.get_gatt_services() {
                        Ok(_) => break 'device_loop,
                        Err(e) => println!("{:?}", e),
                    }
                } else {
                    println!("could not connect");
                }
            }
        }
        println!("");
    }
    adapter.stop_discovery().ok();
    if !try!(device.is_connected()) {
        return Err(Box::from("No connectable device found"));
    }
    let services = try!(device.get_gatt_services());
    for service in services {
        let s = Service::new(service.clone());
        println!("{:?}", s);
        let characteristics = try!(s.get_gatt_characteristics());
        for characteristic in characteristics {
            let c = Characteristic::new(characteristic.clone());
            println!("{:?}", c);
            println!("Value: {:?}", c.read_value(None));
            let descriptors = try!(c.get_gatt_descriptors());
            for descriptor in descriptors {
                let d = Descriptor::new(descriptor.clone());
                println!("{:?}", d);
                println!("Value: {:?}", d.read_value(None));
            }

        }
    }
    try!(device.disconnect());
    Ok(())
}

fn main() {
    match test2() {
         Ok(_) => (),
         Err(e) => println!("{:?}", e),
     }
}
<|endoftext|>


<commit_before>#![allow(unused_variables,unused_must_use)]
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate hex;

use std::net::ToSocketAddrs;
use std::thread;
use std::env;
use std::io::stdout;
use sozu::network;
use sozu::logging::{Logger,LoggerBackend};
use sozu_command::messages;
use sozu_command::channel::Channel;

fn main() {
  if env::var("RUST_LOG").is_ok() {
   Logger::init("EXAMPLE".to_string(), &env::var("RUST_LOG").expect("could not get the RUST_LOG env var"), LoggerBackend::Stdout(stdout()));
  } else {
   Logger::init("EXAMPLE".to_string(), "info", LoggerBackend::Stdout(stdout()));
  }

  info!("MAIN\tstarting up");

  metrics_set_up!("127.0.0.1", 8125);
  gauge!("sozu.TEST", 42);

  let config = messages::HttpProxyConfiguration {
    front: "127.0.0.1:8080".parse().expect("could not parse address"),
    ..Default::default()
  };

  let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    network::http::start(config, channel, max_buffers, buffer_size);
  });

  let http_front = messages::HttpFront {
    app_id:     String::from("app_1"),
    hostname:   String::from("lolcatho.st"),
    path_begin: String::from("/")
  };

  let http_instance = messages::Instance {
    app_id:      String::from("app_1"),
    instance_id: String::from("app_1-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command.write_message(&messages::OrderMessage {
    id:    String::from("ID_ABCD"),
    order: messages::Order::AddHttpFront(http_front)
  });

  command.write_message(&messages::OrderMessage {
    id:    String::from("ID_EFGH"),
    order: messages::Order::AddInstance(http_instance)
  });

  info!("MAIN\tHTTP -> {:?}", command.read_message());
  info!("MAIN\tHTTP -> {:?}", command.read_message());

  let config = messages::HttpsProxyConfiguration {
    front: "127.0.0.1:8443".parse().expect("could not parse address"),
    cipher_list: String::from("ECDHE-ECDSA-CHACHA20-POLY1305:\
    ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
    ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:\
    DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\
    ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:\
    ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:\
    ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\
    ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
    DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:\
    ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:\
    AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
    AES256-SHA:DES-CBC3-SHA:!DSS"),

    ..Default::default()
  };

  let (mut command2, channel2) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg2 = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    network::https::start(config, channel2, max_buffers, buffer_size);
  });

  let cert1 = include_str!("../assets/certificate.pem");
  let key1  = include_str!("../assets/key.pem");

  let certificate_and_key = messages::CertificateAndKey {
    certificate:       String::from(cert1),
    key:               String::from(key1),
    certificate_chain: vec!()
  };
  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_IJKL1"),
    order: messages::Order::AddCertificate(messages::AddCertificate{
      certificate: certificate_and_key,
      names: Vec::new(),
    })
  });

  let tls_front = messages::HttpsFront {
    app_id:      String::from("app_1"),
    hostname:    String::from("lolcatho.st"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("AB2618B674E15243FD02A5618C66509E4840BA60E7D64CEBEC84CDBFECEEE0C5").unwrap()),
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_IJKL2"),
    order: messages::Order::AddHttpsFront(tls_front)
  });
  let tls_instance = messages::Instance {
    app_id:      String::from("app_1"),
    instance_id: String::from("app_1-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_MNOP"),
    order: messages::Order::AddInstance(tls_instance)
  });

  let cert2 = include_str!("../assets/cert_test.pem");
  let key2  = include_str!("../assets/key_test.pem");

  let certificate_and_key2 = messages::CertificateAndKey {
    certificate: String::from(cert2),
    key: String::from(key2),
    certificate_chain: vec!()
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_QRST1"),
    order: messages::Order::AddCertificate(messages::AddCertificate {
      certificate: certificate_and_key2,
      names: Vec::new(),
    })
  });

  let tls_front2 = messages::HttpsFront {
    app_id:      String::from("app_2"),
    hostname:    String::from("test.local"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("7E8EBF9AD0645AB755A2E51EB3734B91D4ACACEF1F28AD9D96D9385487FAE6E6").unwrap()),
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_QRST2"),
    order: messages::Order::AddHttpsFront(tls_front2)
  });

  let tls_instance2 = messages::Instance {
    app_id:      String::from("app_2"),
    instance_id: String::from("app_2-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_UVWX"),
    order: messages::Order::AddInstance(tls_instance2)
  });

  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());

  let _ = jg.join();
  info!("MAIN\tgood bye");
}

<commit_msg>missing macro arguments<commit_after>#![allow(unused_variables,unused_must_use)]
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate hex;

use std::net::ToSocketAddrs;
use std::thread;
use std::env;
use std::io::stdout;
use sozu::network;
use sozu::logging::{Logger,LoggerBackend};
use sozu_command::messages;
use sozu_command::channel::Channel;

fn main() {
  if env::var("RUST_LOG").is_ok() {
   Logger::init("EXAMPLE".to_string(), &env::var("RUST_LOG").expect("could not get the RUST_LOG env var"), LoggerBackend::Stdout(stdout()));
  } else {
   Logger::init("EXAMPLE".to_string(), "info", LoggerBackend::Stdout(stdout()));
  }

  info!("MAIN\tstarting up");

  metrics_set_up!("127.0.0.1", 8125, "main".to_string(), false);
  gauge!("sozu.TEST", 42);

  let config = messages::HttpProxyConfiguration {
    front: "127.0.0.1:8080".parse().expect("could not parse address"),
    ..Default::default()
  };

  let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    network::http::start(config, channel, max_buffers, buffer_size);
  });

  let http_front = messages::HttpFront {
    app_id:     String::from("app_1"),
    hostname:   String::from("lolcatho.st"),
    path_begin: String::from("/")
  };

  let http_instance = messages::Instance {
    app_id:      String::from("app_1"),
    instance_id: String::from("app_1-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command.write_message(&messages::OrderMessage {
    id:    String::from("ID_ABCD"),
    order: messages::Order::AddHttpFront(http_front)
  });

  command.write_message(&messages::OrderMessage {
    id:    String::from("ID_EFGH"),
    order: messages::Order::AddInstance(http_instance)
  });

  info!("MAIN\tHTTP -> {:?}", command.read_message());
  info!("MAIN\tHTTP -> {:?}", command.read_message());

  let config = messages::HttpsProxyConfiguration {
    front: "127.0.0.1:8443".parse().expect("could not parse address"),
    cipher_list: String::from("ECDHE-ECDSA-CHACHA20-POLY1305:\
    ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
    ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:\
    DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\
    ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:\
    ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:\
    ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\
    ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
    DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:\
    ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:\
    AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
    AES256-SHA:DES-CBC3-SHA:!DSS"),

    ..Default::default()
  };

  let (mut command2, channel2) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg2 = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    network::https::start(config, channel2, max_buffers, buffer_size);
  });

  let cert1 = include_str!("../assets/certificate.pem");
  let key1  = include_str!("../assets/key.pem");

  let certificate_and_key = messages::CertificateAndKey {
    certificate:       String::from(cert1),
    key:               String::from(key1),
    certificate_chain: vec!()
  };
  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_IJKL1"),
    order: messages::Order::AddCertificate(messages::AddCertificate{
      certificate: certificate_and_key,
      names: Vec::new(),
    })
  });

  let tls_front = messages::HttpsFront {
    app_id:      String::from("app_1"),
    hostname:    String::from("lolcatho.st"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("AB2618B674E15243FD02A5618C66509E4840BA60E7D64CEBEC84CDBFECEEE0C5").unwrap()),
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_IJKL2"),
    order: messages::Order::AddHttpsFront(tls_front)
  });
  let tls_instance = messages::Instance {
    app_id:      String::from("app_1"),
    instance_id: String::from("app_1-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_MNOP"),
    order: messages::Order::AddInstance(tls_instance)
  });

  let cert2 = include_str!("../assets/cert_test.pem");
  let key2  = include_str!("../assets/key_test.pem");

  let certificate_and_key2 = messages::CertificateAndKey {
    certificate: String::from(cert2),
    key: String::from(key2),
    certificate_chain: vec!()
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_QRST1"),
    order: messages::Order::AddCertificate(messages::AddCertificate {
      certificate: certificate_and_key2,
      names: Vec::new(),
    })
  });

  let tls_front2 = messages::HttpsFront {
    app_id:      String::from("app_2"),
    hostname:    String::from("test.local"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("7E8EBF9AD0645AB755A2E51EB3734B91D4ACACEF1F28AD9D96D9385487FAE6E6").unwrap()),
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_QRST2"),
    order: messages::Order::AddHttpsFront(tls_front2)
  });

  let tls_instance2 = messages::Instance {
    app_id:      String::from("app_2"),
    instance_id: String::from("app_2-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_UVWX"),
    order: messages::Order::AddInstance(tls_instance2)
  });

  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());

  let _ = jg.join();
  info!("MAIN\tgood bye");
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Tile {
    Empty,
    Wall,
    Block,
    Paddle,
    Ball,
}

use Tile::*;

impl std::convert::From<isize> for Tile {
    fn from(n: isize) -> Self {
        match n {
            0 => Empty,
            1 => Wall,
            2 => Block,
            3 => Paddle,
            4 => Ball,
            _ => panic!("Unrecognized tile: {}", n),
        }
    }
}

type GameState = HashMap<(isize, isize), Tile>;

fn read_gamestate(state: &[isize]) -> GameState {
    state
        .chunks(3)
        .map(|chunk| match chunk {
            [x, y, ty] => ((*x, *y), Tile::from(*ty)),
            _ => panic!("wrong length gamestate"),
        })
        .collect()
}

fn part1(tape: &[isize]) -> usize {
    let output = intcode::Interpreter::new(tape.to_vec())
        .with_input(&[1])
        .run()
        .unwrap_or_else(|err| panic!("Error running intcode: {:?}", err));
    read_gamestate(output.output())
        .values()
        .filter(|ty| **ty == Block)
        .count()
}

fn main() {
    let input: Vec<_> = std::fs::read_to_string(Opt::from_args().input)
        .expect("error reading file")
        .split(',')
        .map(|num| {
            num.trim()
                .parse::<isize>()
                .unwrap_or_else(|err| panic!("could not parse token \"{}\": {:?}", num, err))
        })
        .collect();
    println!("Part 1: {}", part1(&input));
}

#[derive(StructOpt)]
struct Opt {
    #[structopt(parse(from_os_str))]
    input: PathBuf,
}
<commit_msg>2019 day 13 part 2 WiP<commit_after>use std::collections::HashMap;
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Tile {
    Empty,
    Wall,
    Block,
    Paddle,
    Ball,
}

use Tile::*;

impl std::convert::From<isize> for Tile {
    fn from(n: isize) -> Self {
        match n {
            0 => Empty,
            1 => Wall,
            2 => Block,
            3 => Paddle,
            4 => Ball,
            _ => panic!("Unrecognized tile: {}", n),
        }
    }
}

#[derive(Debug)]
struct GameState {
    board: HashMap<(isize, isize), Tile>,
    score: Option<isize>,
}

impl GameState {
    fn ball_pos(&self) -> (isize, isize) {
        *self
            .board
            .iter()
            .find(|(_, ty)| **ty == Ball)
            .expect("No ball found")
            .0
    }

    fn paddle_x(&self) -> isize {
        self.board
            .iter()
            .find(|(_, ty)| **ty == Paddle)
            .expect("No paddle found")
            .0
             .0
    }
}

fn read_gamestate(state: &[isize]) -> GameState {
    let mut score = None;
    let board = state
        .chunks(3)
        .filter_map(|chunk| match chunk {
            [x, y, ty] => {
                if (*x, *y) == (-1, 0) {
                    score = Some(*ty);
                    None
                } else {
                    Some(((*x, *y), Tile::from(*ty)))
                }
            }
            _ => panic!("wrong length gamestate"),
        })
        .collect();
    GameState { board, score }
}

fn part1(tape: &[isize]) -> usize {
    let output = intcode::Interpreter::new(tape.to_vec())
        .with_input(&[1])
        .run()
        .unwrap_or_else(|err| panic!("Error running intcode: {:?}", err));
    read_gamestate(output.output())
        .board
        .values()
        .filter(|ty| **ty == Block)
        .count()
}

fn part2(tape: &[isize]) -> isize {
    let mut tape = tape.to_owned();
    tape[0] = 2;
    let mut bytes_read = 0;
    let mut interpreter = intcode::Interpreter::new(tape).with_input(&[0]);
    let mut last_ball_x: Option<isize> = None;
    let mut state = GameState {
        board: HashMap::new(),
        score: None,
    };
    while let Err((err, prog)) = interpreter.clone().run() {
        if err != intcode::ProgramError::NoMoreInput {
            panic!("Unrecoverable error: {:?}", err);
        }
        {
            let update = read_gamestate(&prog.output()[bytes_read..]);
            for (pos, tile) in update.board.iter() {
                state.board.insert(*pos, *tile);
            }
            state.score = update.score.or(state.score);
        }
        dbg!(state.board.values().filter(|tile| **tile == Block).count());
        if state.board.values().filter(|tile| **tile == Block).count() == 0 {
            break;
        }
        let new_ball_pos = state.ball_pos();
        let expected_ball_x = if let Some(last_ball_x) = last_ball_x {
            let ball_next = (
                new_ball_pos.0 + (new_ball_pos.0 - last_ball_x).signum(),
                new_ball_pos.1,
            );
            if *state.board.get(&ball_next).unwrap_or(&Empty) == Wall {
                last_ball_x
            } else {
                ball_next.0
            }
        } else {
            new_ball_pos.0
        };
        let input = (expected_ball_x - state.paddle_x()).signum();
        dbg!(last_ball_x);
        dbg!(new_ball_pos.0);
        dbg!(expected_ball_x);
        dbg!(state.paddle_x());
        dbg!(input);
        dbg!(state.score);
        bytes_read = prog.output().len();
        last_ball_x = Some(new_ball_pos.0);
        interpreter = prog.with_input(&[input]);
    }
    state.score.unwrap_or(0)
}

fn main() {
    let input: Vec<_> = std::fs::read_to_string(Opt::from_args().input)
        .expect("error reading file")
        .split(',')
        .map(|num| {
            num.trim()
                .parse::<isize>()
                .unwrap_or_else(|err| panic!("could not parse token \"{}\": {:?}", num, err))
        })
        .collect();
    println!("Part 1: {}", part1(&input));
    println!("Part 2: {}", part2(&input));
}

#[derive(StructOpt)]
struct Opt {
    #[structopt(parse(from_os_str))]
    input: PathBuf,
}
<|endoftext|>


<commit_before><commit_msg>Update the docs<commit_after><|endoftext|>


<commit_before>use crate::command_prelude::*;

use cargo::core::{GitReference, SourceId, Workspace};
use cargo::ops;
use cargo::util::IntoUrl;

use cargo_util::paths;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary. Default location is $HOME/.cargo/bin")
        .arg_quiet()
        .arg(
            Arg::new("crate")
                .forbid_empty_values(true)
                .multiple_values(true),
        )
        .arg(
            opt("version", "Specify a version to install")
                .alias("vers")
                .value_name("VERSION")
                .requires("crate"),
        )
        .arg(
            opt("git", "Git URL to install the specified crate from")
                .value_name("URL")
                .conflicts_with_all(&["path", "index", "registry"]),
        )
        .arg(
            opt("branch", "Branch to use when installing from git")
                .value_name("BRANCH")
                .requires("git"),
        )
        .arg(
            opt("tag", "Tag to use when installing from git")
                .value_name("TAG")
                .requires("git"),
        )
        .arg(
            opt("rev", "Specific commit to use when installing from git")
                .value_name("SHA")
                .requires("git"),
        )
        .arg(
            opt("path", "Filesystem path to local crate to install")
                .value_name("PATH")
                .conflicts_with_all(&["git", "index", "registry"]),
        )
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short('f'))
        .arg(opt("no-track", "Do not save tracking information"))
        .arg_features()
        .arg_profile("Install artifacts with the specified profile")
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(
            opt("index", "Registry index to install from")
                .value_name("INDEX")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "registry"]),
        )
        .arg(
            opt("registry", "Registry to use")
                .value_name("REGISTRY")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "index"]),
        )
        .arg_message_format()
        .after_help("Run `cargo help install` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let path = args.value_of_path("path", config);
    if let Some(path) = &path {
        config.reload_rooted_at(path)?;
    } else {
        // TODO: Consider calling set_search_stop_path(home).
        config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
    }

    // In general, we try to avoid normalizing paths in Cargo,
    // but in these particular cases we need it to fix rust-lang/cargo#10283.
    // (Handle `SourceId::for_path` and `Workspace::new`,
    // but not `Config::reload_rooted_at` which is always cwd)
    let path = path.map(|p| paths::normalize_path(&p));

    let krates = args
        .values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.into_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::DefaultBranch
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = &path {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = args.registry(config)? {
        SourceId::alt_registry(config, &registry)?
    } else if let Some(index) = args.value_of("index") {
        SourceId::for_registry(&index.into_url()?)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    // We only provide workspace information for local crate installation from
    // one of the following sources:
    // - From current working directory (only work for edition 2015).
    // - From a specific local file path (from `--path` arg).
    //
    // This workspace information is for emitting helpful messages from
    // `ArgMatchesExt::compile_options` and won't affect the actual compilation.
    let workspace = if from_cwd {
        args.workspace(config).ok()
    } else if let Some(path) = &path {
        Workspace::new(&path.join("Cargo.toml"), config).ok()
    } else {
        None
    };

    let mut compile_opts = args.compile_options(
        config,
        CompileMode::Build,
        workspace.as_ref(),
        ProfileChecking::Custom,
    )?;

    compile_opts.build_config.requested_profile =
        args.get_profile_name(config, "release", ProfileChecking::Custom)?;

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            config,
            root,
            krates,
            source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
            args.is_present("no-track"),
        )?;
    }
    Ok(())
}
<commit_msg>Make clippy happy<commit_after>use crate::command_prelude::*;

use cargo::core::{GitReference, SourceId, Workspace};
use cargo::ops;
use cargo::util::IntoUrl;

use cargo_util::paths;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary. Default location is $HOME/.cargo/bin")
        .arg_quiet()
        .arg(
            Arg::new("crate")
                .forbid_empty_values(true)
                .multiple_values(true),
        )
        .arg(
            opt("version", "Specify a version to install")
                .alias("vers")
                .value_name("VERSION")
                .requires("crate"),
        )
        .arg(
            opt("git", "Git URL to install the specified crate from")
                .value_name("URL")
                .conflicts_with_all(&["path", "index", "registry"]),
        )
        .arg(
            opt("branch", "Branch to use when installing from git")
                .value_name("BRANCH")
                .requires("git"),
        )
        .arg(
            opt("tag", "Tag to use when installing from git")
                .value_name("TAG")
                .requires("git"),
        )
        .arg(
            opt("rev", "Specific commit to use when installing from git")
                .value_name("SHA")
                .requires("git"),
        )
        .arg(
            opt("path", "Filesystem path to local crate to install")
                .value_name("PATH")
                .conflicts_with_all(&["git", "index", "registry"]),
        )
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short('f'))
        .arg(opt("no-track", "Do not save tracking information"))
        .arg_features()
        .arg_profile("Install artifacts with the specified profile")
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(
            opt("index", "Registry index to install from")
                .value_name("INDEX")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "registry"]),
        )
        .arg(
            opt("registry", "Registry to use")
                .value_name("REGISTRY")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "index"]),
        )
        .arg_message_format()
        .after_help("Run `cargo help install` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let path = args.value_of_path("path", config);
    if let Some(path) = &path {
        config.reload_rooted_at(path)?;
    } else {
        // TODO: Consider calling set_search_stop_path(home).
        config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
    }

    // In general, we try to avoid normalizing paths in Cargo,
    // but in these particular cases we need it to fix rust-lang/cargo#10283.
    // (Handle `SourceId::for_path` and `Workspace::new`,
    // but not `Config::reload_rooted_at` which is always cwd)
    let path = path.map(|p| paths::normalize_path(&p));

    let krates = args
        .values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.into_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::DefaultBranch
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = &path {
        SourceId::for_path(path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = args.registry(config)? {
        SourceId::alt_registry(config, &registry)?
    } else if let Some(index) = args.value_of("index") {
        SourceId::for_registry(&index.into_url()?)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    // We only provide workspace information for local crate installation from
    // one of the following sources:
    // - From current working directory (only work for edition 2015).
    // - From a specific local file path (from `--path` arg).
    //
    // This workspace information is for emitting helpful messages from
    // `ArgMatchesExt::compile_options` and won't affect the actual compilation.
    let workspace = if from_cwd {
        args.workspace(config).ok()
    } else if let Some(path) = &path {
        Workspace::new(&path.join("Cargo.toml"), config).ok()
    } else {
        None
    };

    let mut compile_opts = args.compile_options(
        config,
        CompileMode::Build,
        workspace.as_ref(),
        ProfileChecking::Custom,
    )?;

    compile_opts.build_config.requested_profile =
        args.get_profile_name(config, "release", ProfileChecking::Custom)?;

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            config,
            root,
            krates,
            source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
            args.is_present("no-track"),
        )?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>use crate::discord_client::DiscordClient;
use serenity::{
    model::{channel::Message, gateway::Ready},
    prelude::*,
    client,
    http::Http,
};

pub struct SerenityDiscordClient {
    serenity_client: Client,
}

struct SerenityDiscordHandler {
    serenity_http: Box<Http>,
}

impl DiscordClient for SerenityDiscordClient {
    fn new(token: &str) -> Self {
        println!("valid token: {}", client::validate_token(token).is_ok());
        let serenity_http = Box::new(Http::new_with_token(token));
        let handler = SerenityDiscordHandler { serenity_http };
        let mut serenity_client = Client::new(token, handler).expect("Error creating serenity client");
        println!("created client");
        if let Err(why) = serenity_client.start() {
            println!("An error occurred while running the client: {:?}", why);
        }
        println!("started connection");
        SerenityDiscordClient { serenity_client }
    }

    fn register_command(command: &str) -> Result<(), &'static str> {
        Ok(())
    }

    fn register_prefix(prefix: &str) -> Result<(), &'static str> {
        Ok(())
    }
}

impl EventHandler for SerenityDiscordHandler {
    fn message(&self, _: Context, msg: Message) {
        println!("received message {}", msg.content);
        if msg.content == "!ping" {
            if let Err(why) = msg.channel_id.say(&self.serenity_http, "Pong!") {
                println!("Error sending message: {:?}", why);
            }
        }
    }

    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}<commit_msg>Fix issue where messages were not sending properly via serenity 0.6.x<commit_after>use crate::discord_client::DiscordClient;
use serenity::{
    model::{channel::Message, gateway::Ready},
    prelude::*,
    client,
    http::Http,
};

pub struct SerenityDiscordClient {
    serenity_client: Client,
}

struct SerenityDiscordHandler;

impl DiscordClient for SerenityDiscordClient {
    fn new(token: &str) -> Self {
        println!("valid token: {}", client::validate_token(token).is_ok());
        let serenity_http = Box::new(Http::default());
        let mut serenity_client = Client::new(token, SerenityDiscordHandler).expect("Error creating serenity client");
        println!("created client");
        if let Err(why) = serenity_client.start() {
            println!("An error occurred while running the client: {:?}", why);
        }
        println!("started connection");
        SerenityDiscordClient { serenity_client }
    }

    fn register_command(command: &str) -> Result<(), &'static str> {
        Ok(())
    }

    fn register_prefix(prefix: &str) -> Result<(), &'static str> {
        Ok(())
    }
}

impl EventHandler for SerenityDiscordHandler {
    fn message(&self, ctx: Context, msg: Message) {
        println!("received message {}", msg.content);
        if msg.content == "!ping" {
            if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!") {
                println!("Error sending message: {:?}", why);
            }
        }
    }

    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}<|endoftext|>


<commit_before>use operand::Operand;
use memory::Memory;
use constants::*;
use super::{Result, Size, Exception,OpcodeInstance,generate};

fn decode_destination_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Operand {
    let mode = ((opcode >> 6) & 0b111) as u8;
    let reg_y = ((opcode >> 9) & 0b111) as u8;
    effective_address(size, pc, mem, mode, reg_y)
}

fn decode_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Operand {
    let mode = ((opcode >> 3) & 0b111) as u8;
    let reg_y = (opcode & 0b111) as u8;
    effective_address(size, pc, mem, mode, reg_y)
}

fn effective_address(size: Size, pc: u32, mem: &Memory, mode: u8, reg_y: u8) -> Operand {
    match mode {
        0b000 => Operand::DataRegisterDirect(reg_y),
        0b001 => Operand::AddressRegisterDirect(reg_y),
        0b010 => Operand::AddressRegisterIndirect(reg_y),
        0b011 => Operand::AddressRegisterIndirectWithPostincrement(reg_y),
        0b100 => Operand::AddressRegisterIndirectWithPredecrement(reg_y),
        0b101 => Operand::AddressRegisterIndirectWithDisplacement(reg_y, mem.read_word(pc + 2) as i16),
        0b110 => {
            let (indexinfo, displacement) = decode_extension_word(mem.read_word(pc + 2));
            Operand::AddressRegisterIndirectWithIndex(reg_y, indexinfo, displacement)
        },
        0b111 => match reg_y {
            0b010 => Operand::PcWithDisplacement(mem.read_word(pc + 2) as i16),
            0b011 => {
                let (indexinfo, displacement) = decode_extension_word(mem.read_word(pc + 2));
                Operand::PcWithIndex(indexinfo, displacement)
            },
            0b000 => Operand::AbsoluteWord(mem.read_word(pc + 2)),
            0b001 => Operand::AbsoluteLong((mem.read_word(pc + 2) as u32) << 16 | mem.read_word(pc + 4) as u32),
            0b100 =>
                match size {
                    Size::Byte => Operand::Immediate(size, (mem.read_word(pc + 2) & 0xFF) as u32),
                    Size::Word => Operand::Immediate(size, mem.read_word(pc + 2) as u32),
                    Size::Long => Operand::Immediate(size, (mem.read_word(pc + 2) as u32) << 16 | mem.read_word(pc + 4) as u32),
                    Size::Unsized => panic!("unsized Immediate"),
                },
            _ => panic!("Unknown addressing mode {:03b} reg {:03b}", mode, reg_y),
        },
        _ => panic!("Unknown addressing mode {:03b} reg {:03b}", mode, reg_y),
    }
}

fn decode_extension_word(extension: u16) -> (u8, i8) {
    // top four bits = (D/A RRR) matches our register array layout
    let xreg_ndx_size = (extension>>12) as u8;
    let displacement = extension as i8;
    (xreg_ndx_size, displacement)
}
#[allow(unused_variables)]
fn decode_dx(opcode: u16, pc: u32, mem: &Memory) -> Operand {
    Operand::DataRegisterDirect(((opcode >> 9) & 7) as u8)
}
#[allow(unused_variables)]
fn decode_ax(opcode: u16, pc: u32, mem: &Memory) -> Operand {
    Operand::AddressRegisterDirect(((opcode >> 9) & 7) as u8)
}
fn decode_imm(size: Size, pc: u32, mem: &Memory) -> Operand {
    match size {
        Size::Byte => Operand::Immediate(size, (mem.read_word(pc+2) & 0xFF) as u32),
        Size::Word => Operand::Immediate(size, mem.read_word(pc+2) as u32),
        Size::Long => Operand::Immediate(size, (mem.read_word(pc+2) as u32) << 16 | mem.read_word(pc+4) as u32),
        Size::Unsized => panic!("unsized Immediate"),
    }
}
pub fn decode_ea_sr(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), Operand::StatusRegister(Size::Word)]
}
pub fn decode_ea_ccr(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), Operand::StatusRegister(Size::Byte)]
}
pub fn decode_ea_dx(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), decode_dx(opcode, pc, mem)]
}
pub fn decode_ea_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    let src = decode_ea(opcode, size, pc, mem);
    let dst = decode_destination_ea(opcode, size, pc + src.extension_words() * 2, mem);
    vec![src, dst]
}
pub fn decode_ea_ax(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), decode_ax(opcode, pc, mem)]
}
pub fn decode_dx_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_dx(opcode, pc, mem), decode_ea(opcode, size, pc, mem)]
}
pub fn decode_imm_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    let imm = decode_imm(size, pc, mem);
    vec![imm, decode_ea(opcode, size, pc + imm.extension_words()*2, mem)]
}

/* Check if opcode is using a valid ea mode */
pub fn valid_ea(opcode: u16, mask: u16) -> bool
{
    if mask == 0 {
        true
    } else {
        match opcode & 0x3f {
            0x00 ... 0x07 => (mask & EA_DATA_REGISTER_DIRECT) != 0,
            0x08 ... 0x0f => (mask & EA_ADDRESS_REGISTER_DIRECT) != 0,
            0x10 ... 0x17 => (mask & EA_ADDRESS_REGISTER_INDIRECT) != 0,
            0x18 ... 0x1f => (mask & EA_ARI_POSTINCREMENT) != 0,
            0x20 ... 0x27 => (mask & EA_ARI_PREDECREMENT) != 0,
            0x28 ... 0x2f => (mask & EA_ARI_DISPLACEMENT) != 0,
            0x30 ... 0x37 => (mask & EA_ARI_INDEX) != 0,
            0x38 => (mask & EA_ABSOLUTE_SHORT) != 0,
            0x39 => (mask & EA_ABSOLUTE_LONG) != 0,
            0x3a => (mask & EA_PC_DISPLACEMENT) != 0,
            0x3b => (mask & EA_PC_INDEX) != 0,
            0x3c => (mask & EA_IMMEDIATE) != 0,
            _ => false
        }
    }
}

pub fn valid_ea_ea(opcode: u16, mask: u16) -> bool
{
    if mask == 0 {
        true
    } else {
        // normally ea are the 6 least significant bits structured as mmmrrr and
        // we need to swap and shift that into place from rrrmmm000000
        let mode = ((opcode >> 3) & 0b111000);
        let reg_y = ((opcode >> 9) & 0b111);
        let swapped_mask = ((mask >> 3) & 0b111000) | ((mask >> 9) & 0b111);
        if opcode == 0x2e7c {
            println!("valid_ea_ea: pcode {:016b}, mask {:016b}, mode | reg_y {:016b} swapped_mask", opcode, mask, mode | reg_y)
        }
        valid_ea(opcode, mask) && valid_ea(mode | reg_y, swapped_mask)
    }
}

pub fn disassemble_first(mem: &Memory) -> OpcodeInstance {
    disassemble(0, mem).unwrap()
}

pub fn disassemble(pc: u32, mem: &Memory) -> Result<OpcodeInstance> {
    let optable = generate();
    let opcode = mem.read_word(pc);
    // println!("opcode read was {:04x}", opcode);
    for op in optable {
        if ((opcode as u32) & op.mask) == op.matching && (op.validator)(opcode, op.ea_mask) {
            let decoder = op.decoder;
            return Ok(OpcodeInstance {mnemonic: op.mnemonic, size: op.size, operands: decoder(opcode, op.size, pc, mem)});
        } else if ((opcode as u32) & op.mask) == op.matching {
            println!("{:04x}: match for {} without passing validator", opcode, op.mnemonic);
        }
    }
    Err(Exception::IllegalInstruction(opcode, pc))
}

#[cfg(test)]
mod tests {
    use operand::Operand;
    use memory::MemoryVec;
    use super::disassemble_first;
    use super::super::Size;

    #[test]
    fn decodes_add_8_er() {
        let mem = MemoryVec::new16(0, vec![0xd411]);
        let inst = disassemble_first(&mem);
        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[0]);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[1]);
        assert_eq!("(A1)", format!("{}", inst.operands[0]));
        assert_eq!("D2", format!("{}", inst.operands[1]));
        assert_eq!("ADD.B\t(A1),D2", format!("{}", inst));
    }
    #[test]
    fn decodes_add_8_re() {
        let mem = MemoryVec::new16(0, vec![0xd511]);
        let inst = disassemble_first(&mem);

        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[0]);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[1]);
        assert_eq!("D2", format!("{}", inst.operands[0]));
        assert_eq!("(A1)", format!("{}", inst.operands[1]));
        assert_eq!("ADD.B\tD2,(A1)", format!("{}", inst));
    }

    #[test]
    fn two_word_decode_imm_ea() {
        // ADDI #$12,$34(A0) is 0x0668 0x0012 0x0034
        let opcode = 0x0668;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x0012, 0x0034]) ;
        let ops = super::decode_imm_ea(opcode, Size::Byte, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Byte, 0x12));
        assert_eq!(ops[1], Operand::AddressRegisterIndirectWithDisplacement(0, 0x34));
    }
    #[test]
    fn three_word_decode_imm_ea_di() {
        // ADDI.L #$1F,$77(A6) is 0x06AE 0x0000 0x001F 0x0077
        let opcode = 0x06AE;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x0000, 0x001F, 0x0077]);
        let ops = super::decode_imm_ea(opcode, Size::Long, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Long, 0x1F));
        assert_eq!(ops[1], Operand::AddressRegisterIndirectWithDisplacement(6, 0x77));
    }
    #[test]
    fn three_word_decode_imm_ea_ix() {
        // ADDI.L #$1F00A4,52(A5,D2) is 0x06B5 0x001F 0x00A4 0x2034
        let opcode = 0x06B5;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x001F, 0x00A4, 0x2034]);
        let ops = super::decode_imm_ea(opcode, Size::Long, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Long, 0x1F00A4));
        assert_eq!(ops[1], Operand::AddressRegisterIndirectWithIndex(5, 2, 0x34));
    }
    #[test]
    fn four_word_decode_imm_ea_al() {
        // ADDI.L #$1F00A4,$12345678 is 0x06B9 0x001F 0x00A4 0x1234 0x5678
        let opcode = 0x06B9;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x001F, 0x00A4, 0x1234, 0x5678]);
        let ops = super::decode_imm_ea(opcode, Size::Long, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Long, 0x1F00A4));
        assert_eq!(ops[1], Operand::AbsoluteLong(0x12345678));
    }
}

<commit_msg>Rename mask param to ea_mask<commit_after>use operand::Operand;
use memory::Memory;
use constants::*;
use super::{Result, Size, Exception,OpcodeInstance,generate};

fn decode_destination_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Operand {
    let mode = ((opcode >> 6) & 0b111) as u8;
    let reg_y = ((opcode >> 9) & 0b111) as u8;
    effective_address(size, pc, mem, mode, reg_y)
}

fn decode_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Operand {
    let mode = ((opcode >> 3) & 0b111) as u8;
    let reg_y = (opcode & 0b111) as u8;
    effective_address(size, pc, mem, mode, reg_y)
}

fn effective_address(size: Size, pc: u32, mem: &Memory, mode: u8, reg_y: u8) -> Operand {
    match mode {
        0b000 => Operand::DataRegisterDirect(reg_y),
        0b001 => Operand::AddressRegisterDirect(reg_y),
        0b010 => Operand::AddressRegisterIndirect(reg_y),
        0b011 => Operand::AddressRegisterIndirectWithPostincrement(reg_y),
        0b100 => Operand::AddressRegisterIndirectWithPredecrement(reg_y),
        0b101 => Operand::AddressRegisterIndirectWithDisplacement(reg_y, mem.read_word(pc + 2) as i16),
        0b110 => {
            let (indexinfo, displacement) = decode_extension_word(mem.read_word(pc + 2));
            Operand::AddressRegisterIndirectWithIndex(reg_y, indexinfo, displacement)
        },
        0b111 => match reg_y {
            0b010 => Operand::PcWithDisplacement(mem.read_word(pc + 2) as i16),
            0b011 => {
                let (indexinfo, displacement) = decode_extension_word(mem.read_word(pc + 2));
                Operand::PcWithIndex(indexinfo, displacement)
            },
            0b000 => Operand::AbsoluteWord(mem.read_word(pc + 2)),
            0b001 => Operand::AbsoluteLong((mem.read_word(pc + 2) as u32) << 16 | mem.read_word(pc + 4) as u32),
            0b100 =>
                match size {
                    Size::Byte => Operand::Immediate(size, (mem.read_word(pc + 2) & 0xFF) as u32),
                    Size::Word => Operand::Immediate(size, mem.read_word(pc + 2) as u32),
                    Size::Long => Operand::Immediate(size, (mem.read_word(pc + 2) as u32) << 16 | mem.read_word(pc + 4) as u32),
                    Size::Unsized => panic!("unsized Immediate"),
                },
            _ => panic!("Unknown addressing mode {:03b} reg {:03b}", mode, reg_y),
        },
        _ => panic!("Unknown addressing mode {:03b} reg {:03b}", mode, reg_y),
    }
}

fn decode_extension_word(extension: u16) -> (u8, i8) {
    // top four bits = (D/A RRR) matches our register array layout
    let xreg_ndx_size = (extension>>12) as u8;
    let displacement = extension as i8;
    (xreg_ndx_size, displacement)
}
#[allow(unused_variables)]
fn decode_dx(opcode: u16, pc: u32, mem: &Memory) -> Operand {
    Operand::DataRegisterDirect(((opcode >> 9) & 7) as u8)
}
#[allow(unused_variables)]
fn decode_ax(opcode: u16, pc: u32, mem: &Memory) -> Operand {
    Operand::AddressRegisterDirect(((opcode >> 9) & 7) as u8)
}
fn decode_imm(size: Size, pc: u32, mem: &Memory) -> Operand {
    match size {
        Size::Byte => Operand::Immediate(size, (mem.read_word(pc+2) & 0xFF) as u32),
        Size::Word => Operand::Immediate(size, mem.read_word(pc+2) as u32),
        Size::Long => Operand::Immediate(size, (mem.read_word(pc+2) as u32) << 16 | mem.read_word(pc+4) as u32),
        Size::Unsized => panic!("unsized Immediate"),
    }
}
pub fn decode_ea_sr(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), Operand::StatusRegister(Size::Word)]
}
pub fn decode_ea_ccr(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), Operand::StatusRegister(Size::Byte)]
}
pub fn decode_ea_dx(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), decode_dx(opcode, pc, mem)]
}
pub fn decode_ea_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    let src = decode_ea(opcode, size, pc, mem);
    let dst = decode_destination_ea(opcode, size, pc + src.extension_words() * 2, mem);
    vec![src, dst]
}
pub fn decode_ea_ax(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_ea(opcode, size, pc, mem), decode_ax(opcode, pc, mem)]
}
pub fn decode_dx_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    vec![decode_dx(opcode, pc, mem), decode_ea(opcode, size, pc, mem)]
}
pub fn decode_imm_ea(opcode: u16, size: Size, pc: u32, mem: &Memory) -> Vec<Operand> {
    let imm = decode_imm(size, pc, mem);
    vec![imm, decode_ea(opcode, size, pc + imm.extension_words()*2, mem)]
}

/* Check if opcode is using a valid ea mode */
pub fn valid_ea(opcode: u16, ea_mask: u16) -> bool
{
    if ea_mask == 0 {
        true
    } else {
        // ea is the lower six bits of the opcode
        match opcode & 0x3f {
            0x00 ... 0x07 => (ea_mask & EA_DATA_REGISTER_DIRECT) != 0,
            0x08 ... 0x0f => (ea_mask & EA_ADDRESS_REGISTER_DIRECT) != 0,
            0x10 ... 0x17 => (ea_mask & EA_ADDRESS_REGISTER_INDIRECT) != 0,
            0x18 ... 0x1f => (ea_mask & EA_ARI_POSTINCREMENT) != 0,
            0x20 ... 0x27 => (ea_mask & EA_ARI_PREDECREMENT) != 0,
            0x28 ... 0x2f => (ea_mask & EA_ARI_DISPLACEMENT) != 0,
            0x30 ... 0x37 => (ea_mask & EA_ARI_INDEX) != 0,
            0x38 => (ea_mask & EA_ABSOLUTE_SHORT) != 0,
            0x39 => (ea_mask & EA_ABSOLUTE_LONG) != 0,
            0x3a => (ea_mask & EA_PC_DISPLACEMENT) != 0,
            0x3b => (ea_mask & EA_PC_INDEX) != 0,
            0x3c => (ea_mask & EA_IMMEDIATE) != 0,
            _ => false
        }
    }
}

pub fn valid_ea_ea(opcode: u16, mask: u16) -> bool
{
    if mask == 0 {
        true
    } else {
        // normally ea are the 6 least significant bits structured as mmmrrr and
        // we need to swap and shift that into place from rrrmmm000000
        let mode = ((opcode >> 3) & 0b111000);
        let reg_y = ((opcode >> 9) & 0b111);
        let swapped_mask = ((mask >> 3) & 0b111000) | ((mask >> 9) & 0b111);
        if opcode == 0x2e7c {
            println!("valid_ea_ea: pcode {:016b}, mask {:016b}, mode | reg_y {:016b} swapped_mask", opcode, mask, mode | reg_y)
        }
        valid_ea(opcode, mask) && valid_ea(mode | reg_y, swapped_mask)
    }
}

pub fn disassemble_first(mem: &Memory) -> OpcodeInstance {
    disassemble(0, mem).unwrap()
}

pub fn disassemble(pc: u32, mem: &Memory) -> Result<OpcodeInstance> {
    let optable = generate();
    let opcode = mem.read_word(pc);
    // println!("opcode read was {:04x}", opcode);
    for op in optable {
        if ((opcode as u32) & op.mask) == op.matching && (op.validator)(opcode, op.ea_mask) {
            let decoder = op.decoder;
            return Ok(OpcodeInstance {mnemonic: op.mnemonic, size: op.size, operands: decoder(opcode, op.size, pc, mem)});
        } else if ((opcode as u32) & op.mask) == op.matching {
            println!("{:04x}: match for {} without passing validator", opcode, op.mnemonic);
        }
    }
    Err(Exception::IllegalInstruction(opcode, pc))
}

#[cfg(test)]
mod tests {
    use operand::Operand;
    use memory::MemoryVec;
    use super::disassemble_first;
    use super::super::Size;

    #[test]
    fn decodes_add_8_er() {
        let mem = MemoryVec::new16(0, vec![0xd411]);
        let inst = disassemble_first(&mem);
        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[0]);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[1]);
        assert_eq!("(A1)", format!("{}", inst.operands[0]));
        assert_eq!("D2", format!("{}", inst.operands[1]));
        assert_eq!("ADD.B\t(A1),D2", format!("{}", inst));
    }
    #[test]
    fn decodes_add_8_re() {
        let mem = MemoryVec::new16(0, vec![0xd511]);
        let inst = disassemble_first(&mem);

        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[0]);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[1]);
        assert_eq!("D2", format!("{}", inst.operands[0]));
        assert_eq!("(A1)", format!("{}", inst.operands[1]));
        assert_eq!("ADD.B\tD2,(A1)", format!("{}", inst));
    }

    #[test]
    fn two_word_decode_imm_ea() {
        // ADDI #$12,$34(A0) is 0x0668 0x0012 0x0034
        let opcode = 0x0668;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x0012, 0x0034]) ;
        let ops = super::decode_imm_ea(opcode, Size::Byte, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Byte, 0x12));
        assert_eq!(ops[1], Operand::AddressRegisterIndirectWithDisplacement(0, 0x34));
    }
    #[test]
    fn three_word_decode_imm_ea_di() {
        // ADDI.L #$1F,$77(A6) is 0x06AE 0x0000 0x001F 0x0077
        let opcode = 0x06AE;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x0000, 0x001F, 0x0077]);
        let ops = super::decode_imm_ea(opcode, Size::Long, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Long, 0x1F));
        assert_eq!(ops[1], Operand::AddressRegisterIndirectWithDisplacement(6, 0x77));
    }
    #[test]
    fn three_word_decode_imm_ea_ix() {
        // ADDI.L #$1F00A4,52(A5,D2) is 0x06B5 0x001F 0x00A4 0x2034
        let opcode = 0x06B5;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x001F, 0x00A4, 0x2034]);
        let ops = super::decode_imm_ea(opcode, Size::Long, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Long, 0x1F00A4));
        assert_eq!(ops[1], Operand::AddressRegisterIndirectWithIndex(5, 2, 0x34));
    }
    #[test]
    fn four_word_decode_imm_ea_al() {
        // ADDI.L #$1F00A4,$12345678 is 0x06B9 0x001F 0x00A4 0x1234 0x5678
        let opcode = 0x06B9;
        let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x001F, 0x00A4, 0x1234, 0x5678]);
        let ops = super::decode_imm_ea(opcode, Size::Long, 0, dasm_mem);
        assert_eq!(ops[0], Operand::Immediate(Size::Long, 0x1F00A4));
        assert_eq!(ops[1], Operand::AbsoluteLong(0x12345678));
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::config::{Config, ProjectConfig};
use common::NamedItem;
use graphql_ir::{Directive, FragmentDefinition, OperationDefinition};
use graphql_transforms::{
    is_preloadable_operation, DATA_DRIVEN_DEPENDENCY_METADATA_KEY, INLINE_DATA_CONSTANTS,
};
use relay_codegen::{build_request_params, Printer};
use relay_typegen::generate_fragment_type;
use schema::Schema;
use signedsource::{sign_file, SIGNING_TOKEN};
use std::fmt::{Result, Write};
use std::sync::Arc;

pub enum ArtifactContent {
    Operation {
        normalization_operation: Arc<OperationDefinition>,
        reader_operation: Arc<OperationDefinition>,
        typegen_operation: Arc<OperationDefinition>,
        source_hash: String,
        text: String,
        id_and_text_hash: Option<(String, String)>,
    },
    Fragment {
        reader_fragment: Arc<FragmentDefinition>,
        typegen_fragment: Arc<FragmentDefinition>,
        source_hash: String,
    },
    SplitOperation {
        normalization_operation: Arc<OperationDefinition>,
        source_hash: String,
    },
    Generic {
        content: Vec<u8>,
    },
}

impl ArtifactContent {
    pub fn as_bytes(
        &self,
        config: &Config,
        project_config: &ProjectConfig,
        printer: &mut Printer,
        schema: &Schema,
    ) -> Vec<u8> {
        match self {
            ArtifactContent::Operation {
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash,
                text,
                id_and_text_hash,
            } => generate_operation(
                config,
                project_config,
                printer,
                schema,
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash.into(),
                text,
                id_and_text_hash,
            ),
            ArtifactContent::SplitOperation {
                normalization_operation,
                source_hash,
            } => generate_split_operation(
                config,
                printer,
                schema,
                normalization_operation,
                source_hash,
            ),
            ArtifactContent::Fragment {
                reader_fragment,
                typegen_fragment,
                source_hash,
            } => generate_fragment(
                config,
                project_config,
                printer,
                schema,
                reader_fragment,
                typegen_fragment,
                source_hash,
            ),
            ArtifactContent::Generic { content } => content.clone(),
        }
    }
}

fn write_data_driven_dependency_annotation(
    content: &mut String,
    data_driven_dependency_directive: &Directive,
) -> Result {
    for arg in &data_driven_dependency_directive.arguments {
        let value = match arg.value.item {
            graphql_ir::Value::Constant(graphql_ir::ConstantValue::String(value)) => value,
            _ => panic!("Unexpected argument value for @__dataDrivenDependencyMetadata directive"),
        };
        writeln!(
            content,
            "// @dataDrivenDependency {} {}",
            arg.name.item, value
        )?;
    }

    Ok(())
}

#[allow(clippy::too_many_arguments)]
fn generate_operation(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    normalization_operation: &OperationDefinition,
    reader_operation: &OperationDefinition,
    typegen_operation: &OperationDefinition,
    source_hash: String,
    text: &str,
    id_and_text_hash: &Option<(String, String)>,
) -> Vec<u8> {
    let mut request_parameters = build_request_params(&normalization_operation);
    let operation_hash: Option<String> = if let Some((id, text_hash)) = id_and_text_hash {
        request_parameters.id = Some(id.clone());
        Some(text_hash.clone())
    } else {
        request_parameters.text = Some(text.into());
        None
    };
    let operation_fragment = FragmentDefinition {
        name: reader_operation.name,
        variable_definitions: reader_operation.variable_definitions.clone(),
        selections: reader_operation.selections.clone(),
        used_global_variables: Default::default(),
        directives: reader_operation.directives.clone(),
        type_condition: reader_operation.type_,
    };
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    if let Some(operation_hash) = operation_hash {
        writeln!(content, " * @relayHash {}", operation_hash).unwrap();
    }
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    if let Some(id) = &request_parameters.id {
        writeln!(content, "// @relayRequestID {}", id).unwrap();
    }
    if project_config.variable_names_comment {
        if normalization_operation.variable_definitions.is_empty() {
            writeln!(content, "// @relayVariables").unwrap();
        } else {
            let mut variable_names: Vec<_> = normalization_operation
                .variable_definitions
                .iter()
                .map(|variable_definition| variable_definition.name.item)
                .collect();
            variable_names.sort();
            write!(content, "// @relayVariables").unwrap();
            for name in variable_names {
                write!(content, " {}", name).unwrap();
            }
            writeln!(content).unwrap();
        }
    }
    let data_driven_dependency_metadata = operation_fragment
        .directives
        .named(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY);
    if let Some(data_driven_dependency_metadata) = data_driven_dependency_metadata {
        write_data_driven_dependency_annotation(&mut content, data_driven_dependency_metadata)
            .unwrap();
    }

    if request_parameters.id.is_some() || data_driven_dependency_metadata.is_some() {
        writeln!(content).unwrap();
    }

    writeln!(
        content,
        "/*::\nimport type {{ ConcreteRequest }} from 'relay-runtime';\n{}*/\n",
        relay_typegen::generate_operation_type(
            typegen_operation,
            normalization_operation,
            schema,
            &project_config.typegen_config,
        )
    )
    .unwrap();
    writeln!(content, "/*\n{}*/\n", text).unwrap();
    writeln!(
        content,
        "var node/*: ConcreteRequest*/ = {};\n",
        printer.print_request_deduped(
            schema,
            normalization_operation,
            &operation_fragment,
            request_parameters,
        )
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    // TODO: T67052528 - revisit this, once we move fb-specific transforms under the feature flag
    if is_preloadable_operation(normalization_operation) {
        writeln!(
              content,
              "if (node.params.id != null) {{\n  require('relay-runtime').PreloadableQueryRegistry.set(node.params.id, node);\n}}\n",
          )
          .unwrap();
    }
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_split_operation(
    config: &Config,
    printer: &mut Printer,
    schema: &Schema,
    node: &OperationDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    writeln!(
        content,
        "/*::\nimport type {{ NormalizationSplitOperation }} from 'relay-runtime';\n\n*/\n"
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: NormalizationSplitOperation*/ = {};\n",
        printer.print_operation_deduped(schema, node)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_fragment(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    reader_fragment: &FragmentDefinition,
    typegen_fragment: &FragmentDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    let data_driven_dependency_metadata = reader_fragment
        .directives
        .named(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY);
    if let Some(data_driven_dependency_metadata) = data_driven_dependency_metadata {
        write_data_driven_dependency_annotation(&mut content, data_driven_dependency_metadata)
            .unwrap();

        writeln!(content).unwrap();
    }

    let reader_node_flow_type = if reader_fragment
        .directives
        .named(INLINE_DATA_CONSTANTS.directive_name)
        .is_some()
    {
        "ReaderInlineDataFragment"
    } else {
        "ReaderFragment"
    };
    writeln!(
        content,
        "/*::\nimport type {{ {} }} from 'relay-runtime';\n{}*/\n",
        reader_node_flow_type,
        generate_fragment_type(typegen_fragment, schema, &project_config.typegen_config)
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: {}*/ = {};\n",
        reader_node_flow_type,
        printer.print_fragment_deduped(schema, reader_fragment)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn get_content_start(config: &Config) -> String {
    let mut content = String::new();
    writeln!(content, "/**").unwrap();
    if !config.header.is_empty() {
        for header_line in &config.header {
            writeln!(content, " * {}", header_line).unwrap();
        }
        writeln!(content, " *").unwrap();
    }
    content
}
<commit_msg>no longer sort @relayVariables header<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::config::{Config, ProjectConfig};
use common::NamedItem;
use graphql_ir::{Directive, FragmentDefinition, OperationDefinition};
use graphql_transforms::{
    is_preloadable_operation, DATA_DRIVEN_DEPENDENCY_METADATA_KEY, INLINE_DATA_CONSTANTS,
};
use relay_codegen::{build_request_params, Printer};
use relay_typegen::generate_fragment_type;
use schema::Schema;
use signedsource::{sign_file, SIGNING_TOKEN};
use std::fmt::{Result, Write};
use std::sync::Arc;

pub enum ArtifactContent {
    Operation {
        normalization_operation: Arc<OperationDefinition>,
        reader_operation: Arc<OperationDefinition>,
        typegen_operation: Arc<OperationDefinition>,
        source_hash: String,
        text: String,
        id_and_text_hash: Option<(String, String)>,
    },
    Fragment {
        reader_fragment: Arc<FragmentDefinition>,
        typegen_fragment: Arc<FragmentDefinition>,
        source_hash: String,
    },
    SplitOperation {
        normalization_operation: Arc<OperationDefinition>,
        source_hash: String,
    },
    Generic {
        content: Vec<u8>,
    },
}

impl ArtifactContent {
    pub fn as_bytes(
        &self,
        config: &Config,
        project_config: &ProjectConfig,
        printer: &mut Printer,
        schema: &Schema,
    ) -> Vec<u8> {
        match self {
            ArtifactContent::Operation {
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash,
                text,
                id_and_text_hash,
            } => generate_operation(
                config,
                project_config,
                printer,
                schema,
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash.into(),
                text,
                id_and_text_hash,
            ),
            ArtifactContent::SplitOperation {
                normalization_operation,
                source_hash,
            } => generate_split_operation(
                config,
                printer,
                schema,
                normalization_operation,
                source_hash,
            ),
            ArtifactContent::Fragment {
                reader_fragment,
                typegen_fragment,
                source_hash,
            } => generate_fragment(
                config,
                project_config,
                printer,
                schema,
                reader_fragment,
                typegen_fragment,
                source_hash,
            ),
            ArtifactContent::Generic { content } => content.clone(),
        }
    }
}

fn write_data_driven_dependency_annotation(
    content: &mut String,
    data_driven_dependency_directive: &Directive,
) -> Result {
    for arg in &data_driven_dependency_directive.arguments {
        let value = match arg.value.item {
            graphql_ir::Value::Constant(graphql_ir::ConstantValue::String(value)) => value,
            _ => panic!("Unexpected argument value for @__dataDrivenDependencyMetadata directive"),
        };
        writeln!(
            content,
            "// @dataDrivenDependency {} {}",
            arg.name.item, value
        )?;
    }

    Ok(())
}

#[allow(clippy::too_many_arguments)]
fn generate_operation(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    normalization_operation: &OperationDefinition,
    reader_operation: &OperationDefinition,
    typegen_operation: &OperationDefinition,
    source_hash: String,
    text: &str,
    id_and_text_hash: &Option<(String, String)>,
) -> Vec<u8> {
    let mut request_parameters = build_request_params(&normalization_operation);
    let operation_hash: Option<String> = if let Some((id, text_hash)) = id_and_text_hash {
        request_parameters.id = Some(id.clone());
        Some(text_hash.clone())
    } else {
        request_parameters.text = Some(text.into());
        None
    };
    let operation_fragment = FragmentDefinition {
        name: reader_operation.name,
        variable_definitions: reader_operation.variable_definitions.clone(),
        selections: reader_operation.selections.clone(),
        used_global_variables: Default::default(),
        directives: reader_operation.directives.clone(),
        type_condition: reader_operation.type_,
    };
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    if let Some(operation_hash) = operation_hash {
        writeln!(content, " * @relayHash {}", operation_hash).unwrap();
    }
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    if let Some(id) = &request_parameters.id {
        writeln!(content, "// @relayRequestID {}", id).unwrap();
    }
    if project_config.variable_names_comment {
        write!(content, "// @relayVariables").unwrap();
        for variable_definition in &normalization_operation.variable_definitions {
            write!(content, " {}", variable_definition.name.item).unwrap();
        }
        writeln!(content).unwrap();
    }
    let data_driven_dependency_metadata = operation_fragment
        .directives
        .named(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY);
    if let Some(data_driven_dependency_metadata) = data_driven_dependency_metadata {
        write_data_driven_dependency_annotation(&mut content, data_driven_dependency_metadata)
            .unwrap();
    }

    if request_parameters.id.is_some() || data_driven_dependency_metadata.is_some() {
        writeln!(content).unwrap();
    }

    writeln!(
        content,
        "/*::\nimport type {{ ConcreteRequest }} from 'relay-runtime';\n{}*/\n",
        relay_typegen::generate_operation_type(
            typegen_operation,
            normalization_operation,
            schema,
            &project_config.typegen_config,
        )
    )
    .unwrap();
    writeln!(content, "/*\n{}*/\n", text).unwrap();
    writeln!(
        content,
        "var node/*: ConcreteRequest*/ = {};\n",
        printer.print_request_deduped(
            schema,
            normalization_operation,
            &operation_fragment,
            request_parameters,
        )
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    // TODO: T67052528 - revisit this, once we move fb-specific transforms under the feature flag
    if is_preloadable_operation(normalization_operation) {
        writeln!(
              content,
              "if (node.params.id != null) {{\n  require('relay-runtime').PreloadableQueryRegistry.set(node.params.id, node);\n}}\n",
          )
          .unwrap();
    }
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_split_operation(
    config: &Config,
    printer: &mut Printer,
    schema: &Schema,
    node: &OperationDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    writeln!(
        content,
        "/*::\nimport type {{ NormalizationSplitOperation }} from 'relay-runtime';\n\n*/\n"
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: NormalizationSplitOperation*/ = {};\n",
        printer.print_operation_deduped(schema, node)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_fragment(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    reader_fragment: &FragmentDefinition,
    typegen_fragment: &FragmentDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    let data_driven_dependency_metadata = reader_fragment
        .directives
        .named(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY);
    if let Some(data_driven_dependency_metadata) = data_driven_dependency_metadata {
        write_data_driven_dependency_annotation(&mut content, data_driven_dependency_metadata)
            .unwrap();

        writeln!(content).unwrap();
    }

    let reader_node_flow_type = if reader_fragment
        .directives
        .named(INLINE_DATA_CONSTANTS.directive_name)
        .is_some()
    {
        "ReaderInlineDataFragment"
    } else {
        "ReaderFragment"
    };
    writeln!(
        content,
        "/*::\nimport type {{ {} }} from 'relay-runtime';\n{}*/\n",
        reader_node_flow_type,
        generate_fragment_type(typegen_fragment, schema, &project_config.typegen_config)
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: {}*/ = {};\n",
        reader_node_flow_type,
        printer.print_fragment_deduped(schema, reader_fragment)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn get_content_start(config: &Config) -> String {
    let mut content = String::new();
    writeln!(content, "/**").unwrap();
    if !config.header.is_empty() {
        for header_line in &config.header {
            writeln!(content, " * {}", header_line).unwrap();
        }
        writeln!(content, " *").unwrap();
    }
    content
}
<|endoftext|>


<commit_before><commit_msg>!test<commit_after><|endoftext|>