├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── LICENSE-MIT ├── examples └── urbit.rs ├── src ├── jet.rs ├── jets.rs └── lib.rs └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changes by Release 2 | 3 | ## 0.1.0 (2016-04-16) 4 | 5 | - Initial release with proof-of-concept jet implementation and pill 6 | unpacking. 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "urbit" 3 | version = "0.1.0" 4 | authors = ["Risto Saarelma "] 5 | description = "Urbit utilities" 6 | repository = "https://github.com/rsaarelm/urbit-rs" 7 | license = "MIT OR Apache-2.0" 8 | 9 | [dependencies] 10 | fnv = "1.0" 11 | time = "0.1" 12 | num = "0.1" 13 | nock = "0.4" 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Urbit utilities 2 | 3 | To use the pill evaluator example, get a valid urbit pillfile from 4 | somewhere, eg 5 | 6 | curl -o urbit.pill http://bootstrap.urbit.org/latest.pill 7 | 8 | and then do 9 | 10 | cargo run --release --example urbit -- urbit.pill 11 | 12 | ## License 13 | 14 | Licensed under either of 15 | 16 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 17 | 18 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 19 | 20 | at your option. 21 | 22 | ### Contribution 23 | 24 | Unless you explicitly state otherwise, any contribution intentionally submitted 25 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any 26 | additional terms or conditions. 27 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Risto Saarelma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/urbit.rs: -------------------------------------------------------------------------------- 1 | extern crate nock; 2 | extern crate urbit; 3 | extern crate num; 4 | 5 | use std::env; 6 | use std::io::prelude::*; 7 | use std::fs::File; 8 | use num::bigint::BigUint; 9 | use num::traits::One; 10 | use nock::{Nock, Noun, Shape}; 11 | use urbit::VM; 12 | 13 | fn get_size(noun: &Noun) -> BigUint { 14 | noun.fold(|x| { 15 | match x { 16 | Shape::Cell(p, q) => p + q, 17 | _ => One::one(), 18 | } 19 | }) 20 | } 21 | 22 | fn main() { 23 | let mut file = File::open(env::args() 24 | .nth(1) 25 | .expect("Usage urbit [urbit.pill]")) 26 | .unwrap(); 27 | 28 | let mut buf = Vec::new(); 29 | file.read_to_end(&mut buf).unwrap(); 30 | println!("Unpacking pill"); 31 | let pill = urbit::unpack_pill(buf).unwrap(); 32 | 33 | // You can't nock the whole pill as an 34 | let (kernel, arvo) = match pill.get() { 35 | Shape::Cell(kernel, arvo) => ((*kernel).clone(), (*arvo).clone()), 36 | _ => panic!("bad"), 37 | }; 38 | println!("Unpacked pill"); 39 | 40 | println!("Kernel has {} atoms", get_size(&kernel)); 41 | println!("Arvo has {} atoms", get_size(&arvo)); 42 | 43 | let mut vm = VM::new(); 44 | 45 | println!("Nocking kernel"); 46 | let noun = vm.nock_on(Noun::from(0u32), kernel).unwrap(); 47 | vm.print_status(); 48 | println!("Kernel nocked, subject has {} atoms", get_size(&noun)); 49 | println!("{}", noun); 50 | 51 | println!("TODO: Boot arvo"); 52 | // FIXME: This isn't the right way to boot... 53 | // println!("Nocking arvo"); 54 | // let noun = vm.nock_on(Noun::from(0u32), arvo).unwrap(); 55 | // vm.print_status(); 56 | // println!("Arvo nocked, subject has {} atoms", get_size(&noun)); 57 | // println!("{}", noun); 58 | } 59 | -------------------------------------------------------------------------------- /src/jet.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | use std::hash; 4 | use std::iter::FromIterator; 5 | use std::collections::HashMap; 6 | use nock::{self, Noun, FromNoun, ToNoun, NockError, NockResult}; 7 | use jets; 8 | 9 | #[derive(Clone, PartialEq, Eq, Debug)] 10 | pub struct JetError(pub String); 11 | 12 | pub type JetResult = Result; 13 | 14 | impl fmt::Display for JetError { 15 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 16 | write!(f, "{}", self.0) 17 | } 18 | } 19 | 20 | impl Error for JetError { 21 | fn description(&self) -> &str { 22 | &self.0[..] 23 | } 24 | 25 | fn cause(&self) -> Option<&Error> { 26 | None 27 | } 28 | } 29 | 30 | pub struct Jet { 31 | pub name: String, 32 | pub jet: Option NockResult>, 33 | pub battery: Noun, 34 | // TODO: What do we do with these? 35 | pub axis: u32, 36 | pub hooks: HashMap, 37 | pub calls: u64, 38 | } 39 | 40 | impl Jet { 41 | pub fn new(name: String, battery: Noun, axis: u32, hooks: Vec<(String, Noun)>) -> Jet { 42 | let jet = match_jet(&name[..]); 43 | Jet { 44 | name: name, 45 | jet: jet, 46 | battery: battery, 47 | axis: axis, 48 | hooks: HashMap::from_iter(hooks.into_iter()), 49 | calls: 0, 50 | } 51 | } 52 | } 53 | 54 | impl hash::Hash for Jet { 55 | fn hash(&self, state: &mut H) { 56 | self.battery.hash(state); 57 | } 58 | } 59 | 60 | /// Wrap a single-argument function as a jet. 61 | /// 62 | /// The argument will be extracted from axis 6 of subject. 63 | #[inline] 64 | fn wrap1(jet_name: &str, f: F, subject: &Noun) -> NockResult 65 | where T1: FromNoun, 66 | U: ToNoun, 67 | F: Fn(T1) -> JetResult 68 | { 69 | let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap(); 70 | let t1: T1 = try!(FromNoun::from_noun(&arg)); 71 | let ret = try!(f(t1).map_err(|e| NockError(format!("jet {} {}", jet_name, e)))); 72 | Ok(ret.to_noun()) 73 | } 74 | 75 | #[inline] 76 | fn wrap2(jet_name: &str, f: F, subject: &Noun) -> NockResult 77 | where T1: FromNoun, 78 | T2: FromNoun, 79 | U: ToNoun, 80 | F: Fn(T1, T2) -> JetResult 81 | { 82 | let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap(); 83 | let (t1, t2): (T1, T2) = try!(FromNoun::from_noun(&arg)); 84 | let ret = try!(f(t1, t2).map_err(|e| NockError(format!("jet {} {}", jet_name, e)))); 85 | Ok(ret.to_noun()) 86 | } 87 | 88 | #[inline] 89 | fn wrap3(jet_name: &str, f: F, subject: &Noun) -> NockResult 90 | where T1: FromNoun, 91 | T2: FromNoun, 92 | T3: FromNoun, 93 | U: ToNoun, 94 | F: Fn(T1, T2, T3) -> JetResult { 95 | let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap(); 96 | let (t1, t2, t3): (T1, T2, T3) = try!(FromNoun::from_noun(&arg)); 97 | let ret = try!(f(t1, t2, t3).map_err(|e| NockError(format!("jet {} {}", jet_name, e)))); 98 | Ok(ret.to_noun()) 99 | } 100 | 101 | /* 102 | /// Give jet full access to the subject. 103 | #[inline] 104 | fn wrap_raw(jet_name: &str, f: F, subject: &Noun) -> NockResult 105 | where U: ToNoun, 106 | F: Fn(&Noun) -> JetResult { 107 | let ret = try!(f(subject).map_err(|e| NockError(format!("jet {} {}", jet_name, e)))); 108 | Ok(ret.to_noun()) 109 | } 110 | */ 111 | 112 | /// Construct a jet matcher from tuples of (internal_jet_function, urbit_jet_name, jet_wrapper_function). 113 | macro_rules! match_jet{ 114 | ($($f:ident: $name:expr, $wrap_fn:ident;)*) => { 115 | $(fn $f(subject: &Noun) -> NockResult { $wrap_fn($name, jets::$f, subject) })* 116 | 117 | fn match_jet(name: &str) -> Option NockResult> { 118 | match name { 119 | $($name => Some($f as fn(&Noun) -> NockResult),)* 120 | _ => None 121 | } 122 | } 123 | } 124 | } 125 | 126 | match_jet!{ 127 | dec: "dec", wrap1; 128 | bex: "bex", wrap1; 129 | add: "add", wrap2; 130 | mul: "mul", wrap2; 131 | sub: "sub", wrap2; 132 | div: "div", wrap2; 133 | lth: "lth", wrap2; 134 | rsh: "rsh", wrap3; 135 | lsh: "lsh", wrap3; 136 | mod_: "mod", wrap2; 137 | mix: "mix", wrap2; 138 | met: "met", wrap2; 139 | mug: "mug", wrap1; 140 | end: "end", wrap3; 141 | cut: "cut", wrap3; 142 | rub: "rub", wrap2; 143 | cue: "cue", wrap1; 144 | } 145 | -------------------------------------------------------------------------------- /src/jets.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | use std::collections::HashMap; 3 | use std::cmp; 4 | use num::{BigUint, FromPrimitive, ToPrimitive, Zero, One}; 5 | use jet::{JetError, JetResult}; 6 | use nock::{self, Noun}; 7 | 8 | /// Return with an error from a jet. 9 | macro_rules! bail( ($($arg:tt)*) => ( return Err(JetError(format!($($arg)*))); )); 10 | 11 | pub fn dec(n: BigUint) -> JetResult { 12 | if n == BigUint::zero() { 13 | bail!("dec 0"); 14 | } 15 | Ok(n - BigUint::one()) 16 | } 17 | 18 | /// Binary exponent, compute 2^a. 19 | pub fn bex(a: usize) -> JetResult { 20 | Ok(BigUint::one() << a) 21 | } 22 | 23 | pub fn add(a: BigUint, b: BigUint) -> JetResult { 24 | Ok(a + b) 25 | } 26 | 27 | pub fn mul(a: BigUint, b: BigUint) -> JetResult { 28 | Ok(a * b) 29 | } 30 | 31 | pub fn sub(a: BigUint, b: BigUint) -> JetResult { 32 | if b > a { 33 | bail!("sub goes negative"); 34 | } 35 | Ok(a - b) 36 | } 37 | 38 | pub fn div(a: BigUint, b: BigUint) -> JetResult { 39 | if b == BigUint::zero() { 40 | bail!("div by zero"); 41 | } 42 | Ok(a / b) 43 | } 44 | 45 | /// Less-than. 46 | pub fn lth(a: BigUint, b: BigUint) -> JetResult { 47 | Ok(a < b) 48 | } 49 | 50 | pub fn rsh(bloq: usize, b: usize, c: BigUint) -> JetResult { 51 | Ok(c >> (b << bloq)) 52 | } 53 | 54 | pub fn lsh(bloq: usize, b: usize, c: BigUint) -> JetResult { 55 | Ok(c << (b << bloq)) 56 | } 57 | 58 | pub fn mod_(a: BigUint, b: BigUint) -> JetResult { 59 | Ok(a % b) 60 | } 61 | 62 | pub fn mix(a: BigUint, b: BigUint) -> JetResult { 63 | Ok(a ^ b) 64 | } 65 | 66 | /// Counts bloq length of atom. 67 | pub fn met(bloq: usize, a: Rc>) -> JetResult { 68 | let bits = nock::msb(&*a) + (1 << bloq) - 1; 69 | Ok(BigUint::from_usize(bits / (1 << bloq)).unwrap()) 70 | } 71 | 72 | pub fn mug(a: Noun) -> JetResult { 73 | Ok(a.mug()) 74 | } 75 | 76 | /// Produces an atom by taking the last `b` blocks of size `bloq` from `c`. 77 | pub fn end(bloq: usize, b: usize, c: Rc>) -> JetResult> { 78 | // Using Rc> lets you access large atoms without copying the atom 79 | // contents. 80 | 81 | assert!(bloq == 3); 82 | let bits = (1 << bloq) * b; 83 | let bytes = cmp::min(((bits + 7) / 8), c.len()); 84 | 85 | let mut ret = c[0..bytes].to_vec(); 86 | // Snip off last bits if bit count isn't byte multiple. 87 | let trailing = bits % 8; 88 | if trailing != 0 { 89 | assert!(ret.len() > 0); 90 | let last_idx = ret.len() - 1; 91 | ret[last_idx] &= (1 << trailing) - 1; 92 | } 93 | Ok(ret) 94 | } 95 | 96 | /// Slices `c` blocks of size `bloq` that are `b` blocks from the end of `d`. 97 | pub fn cut(bloq: usize, (b, c): (usize, usize), d: Rc>) -> JetResult> { 98 | let start_bit = b << bloq; 99 | let end_bit = (start_bit + c) << bloq; 100 | 101 | if start_bit % 8 != 0 || end_bit % 8 != 0 { 102 | bail!("FIXME cut does not support non-byte offsets yet"); 103 | } 104 | 105 | Ok(d[(start_bit / 8)..(end_bit / 8)].to_vec()) 106 | } 107 | 108 | #[inline] 109 | fn bit(data: &[u8], pos: usize) -> bool { 110 | data[pos / 8] & (1 << (pos % 8)) != 0 111 | } 112 | 113 | /// Decode a lenght-encoded atom from a bit stream. 114 | pub fn rub(data: Rc>, pos: usize) -> JetResult<(usize, BigUint)> { 115 | // Length of the prefix in bits is the count of initial zeroes before 116 | // the separator 1. 117 | 118 | let mut p = 0; 119 | 120 | // Assume the first bit is zero even if it isn't. 121 | let mut k = 1; 122 | p += 1; 123 | 124 | while !bit(&data, pos + p) { 125 | k += 1; 126 | p += 1; 127 | } 128 | p += 1; 129 | 130 | // Read the prefix. 131 | let mut b = 0; 132 | if k > 1 { 133 | for i in 0..(k - 2) { 134 | if bit(&data, pos + p) { 135 | b += 1 << i; 136 | } 137 | p += 1; 138 | } 139 | // Add the implicit top 1 to the prefix. 140 | b += 1 << (k - 2); 141 | } 142 | 143 | let mut q: BigUint = Default::default(); 144 | for i in 0..b { 145 | if bit(&data, pos + p) { 146 | q = q + (BigUint::one() << i); 147 | } 148 | p += 1; 149 | } 150 | Ok((p, q)) 151 | } 152 | 153 | /// Decode an encoded cell from a bit stream. 154 | /// 155 | /// Return the Nock noun. 156 | pub fn cue(data: Rc>) -> JetResult { 157 | let (_, noun) = try!(parse(0, data, &mut Default::default())); 158 | return Ok(noun); 159 | 160 | fn parse(mut pos: usize, 161 | data: Rc>, 162 | dict: &mut HashMap) 163 | -> JetResult<(usize, Noun)> { 164 | let key = pos; 165 | if bit(&data, pos) { 166 | pos += 1; 167 | if !bit(&data, pos) { 168 | // 10: encode a pair. 169 | pos += 1; 170 | let (p, left) = try!(parse(pos, data.clone(), dict)); 171 | pos = p; 172 | let (p, right) = try!(parse(pos, data.clone(), dict)); 173 | pos = p; 174 | 175 | let ret = Noun::cell(left, right); 176 | dict.insert(key, ret.clone()); 177 | Ok((pos, ret)) 178 | } else { 179 | // 11: Repeat element 180 | // Read the index in bitstream where the value was first 181 | // encountered. 182 | let (p, q) = try!(rub(data.clone(), pos)); 183 | pos += p; 184 | let key = q.to_usize().unwrap(); 185 | if let Some(x) = dict.get(&key) { 186 | Ok((pos, x.clone())) 187 | } else { 188 | bail!("Bad cell index") 189 | } 190 | } 191 | } else { 192 | // Atom. 193 | let (p, q) = try!(rub(data.clone(), pos)); 194 | pos += p; 195 | let ret = Noun::from(q); 196 | dict.insert(key, ret.clone()); 197 | Ok((pos, ret)) 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate num; 2 | extern crate fnv; 3 | extern crate nock; 4 | 5 | use std::rc::Rc; 6 | use std::collections::HashMap; 7 | use nock::{Nock, Noun, NockError, NockResult, Shape, FromNoun}; 8 | use jet::Jet; 9 | 10 | mod jet; 11 | mod jets; 12 | 13 | /// An Urbit virtual machine. 14 | pub struct VM { 15 | jets: HashMap, 16 | } 17 | 18 | impl Nock for VM { 19 | fn call(&mut self, subject: &Noun, formula: &Noun) -> Option { 20 | if let Some(jet) = self.jets.get_mut(formula) { 21 | jet.calls += 1; 22 | 23 | if let Some(f) = jet.jet { 24 | return Some(f(subject)); 25 | } 26 | } 27 | None 28 | } 29 | 30 | fn hint(&mut self, subject: &Noun, hint: &Noun, c: &Noun) -> Result<(), NockError> { 31 | let (id, clue) = match hint.get() { 32 | Shape::Cell(ref p, ref q) => { 33 | (*p, try!(self.nock_on((*subject).clone(), (*q).clone()))) 34 | } 35 | Shape::Atom(_) => (hint, Noun::from(0u32)), 36 | }; 37 | 38 | // TODO: Handle other hint types than %fast. 39 | if String::from_noun(id).unwrap() == "fast" { 40 | let core = try!(self.nock_on((*subject).clone(), (*c).clone())); 41 | if let Ok((name, axis, hooks)) = parse_fast_clue(&clue) { 42 | if let Shape::Cell(ref battery, _) = core.get() { 43 | if !self.jets.contains_key(battery) { 44 | let jet = Jet::new(name, (*battery).clone(), axis, hooks); 45 | self.jets.insert((*battery).clone(), jet); 46 | } 47 | } else { 48 | return Err(NockError(format!("hint"))); 49 | } 50 | } else { 51 | // println!("Unparseable clue..."); 52 | } 53 | } 54 | Ok(()) 55 | } 56 | } 57 | 58 | impl VM { 59 | pub fn new() -> VM { 60 | VM { jets: HashMap::new() } 61 | } 62 | 63 | pub fn print_status(&self) { 64 | let mut total_count = 0; 65 | let mut jets: Vec<&Jet> = self.jets.iter().map(|(_, x)| x).collect(); 66 | jets.sort_by(|a, b| b.calls.cmp(&a.calls)); 67 | for jet in &jets { 68 | if jet.calls < 100 || (jet.calls as f32) / (total_count as f32) < 1e-6 { 69 | // Don't care about the little things 70 | println!(" ..."); 71 | break; 72 | } 73 | println!("{}{} called {} times", 74 | if jet.jet.is_some() { 75 | '*' 76 | } else { 77 | ' ' 78 | }, 79 | jet.name, 80 | jet.calls); 81 | total_count += jet.calls; 82 | } 83 | } 84 | } 85 | 86 | fn parse_fast_clue(clue: &Noun) -> Result<(String, u32, Vec<(String, Noun)>), NockError> { 87 | if let Some((ref name, ref axis_formula, ref hooks)) = clue.get_122() { 88 | let chum = try!(String::from_noun(name).map_err(|_| NockError(format!("hint")))); 89 | 90 | let axis = if let Shape::Cell(ref a, ref b) = axis_formula.get() { 91 | if let (Some(1), Some(0)) = (a.as_u32(), b.as_u32()) { 92 | 0 93 | } else if let (Some(0), Some(axis)) = (a.as_u32(), b.as_u32()) { 94 | axis 95 | } else { 96 | return Err(NockError(format!("hint"))); 97 | } 98 | } else { 99 | return Err(NockError(format!("hint"))); 100 | }; 101 | 102 | let hooks: Vec<(String, Noun)> = try!(FromNoun::from_noun(hooks) 103 | .map_err(|_| NockError(format!("hint")))); 104 | 105 | Ok((chum, axis, hooks)) 106 | } else { 107 | Err(NockError(format!("hint"))) 108 | } 109 | } 110 | 111 | /// A human-readable hash version. 112 | pub fn symhash(noun: &Noun) -> String { 113 | fn proquint(buf: &mut String, mut b: u16) { 114 | const C: [char; 16] = ['b', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 's', 115 | 't', 'v', 'z']; 116 | const V: [char; 4] = ['a', 'i', 'o', 'u']; 117 | buf.push(C[(b % 16) as usize]); 118 | b >>= 4; 119 | buf.push(V[(b % 4) as usize]); 120 | b >>= 2; 121 | buf.push(C[(b % 16) as usize]); 122 | b >>= 4; 123 | buf.push(V[(b % 4) as usize]); 124 | b >>= 2; 125 | buf.push(C[(b % 16) as usize]); 126 | } 127 | 128 | let mut hash = noun.mug(); 129 | let mut ret = String::new(); 130 | proquint(&mut ret, (hash % 0xFFFF) as u16); 131 | hash >>= 16; 132 | ret.push('-'); 133 | proquint(&mut ret, (hash % 0xFFFF) as u16); 134 | 135 | ret 136 | } 137 | 138 | /// Unpack the data of an Urbit pillfile into a Nock noun. 139 | pub fn unpack_pill(mut buf: Vec) -> jet::JetResult { 140 | // Guarantee that the buffer is made of 32-bit chunks. 141 | while buf.len() % 4 != 0 { 142 | buf.push(0); 143 | } 144 | 145 | jets::cue(Rc::new(buf)) 146 | } 147 | 148 | #[cfg(test)] 149 | mod test { 150 | use nock::Noun; 151 | 152 | #[test] 153 | fn test_read_pill() { 154 | use super::unpack_pill; 155 | 156 | let noun: Noun = "[18.446.744.073.709.551.616 8 [1 0] 8 [1 6 [5 [0 7] 4 0 6] [0 6] 9 2 [0 \ 157 | 2] [4 0 6] 0 7] 9 2 0 1]" 158 | .parse() 159 | .expect("Nock parse error"); 160 | let pill: &[u8] = &[0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 161 | 0xc1, 0x62, 0x83, 0x60, 0x71, 0xd8, 0x85, 0x5b, 0xe2, 0x87, 0x99, 162 | 0xd8, 0x0d, 0xc1, 0x1a, 0x24, 0x43, 0x96, 0xc8, 0x86, 0x10, 0x1d, 163 | 0xc2, 0x32, 0x48, 0x86, 0x4c, 0x06]; 164 | let unpacked = unpack_pill(pill.to_vec()).expect("Pill unpack failed"); 165 | assert_eq!(noun, unpacked); 166 | } 167 | 168 | #[test] 169 | fn test_cue_stack() { 170 | use super::unpack_pill; 171 | 172 | let noun: Noun = "[1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 173 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 174 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 175 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 176 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 177 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 178 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 179 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 180 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 181 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 182 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ 183 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]" 184 | .parse() 185 | .expect("Nock parse error"); 186 | let pill: &[u8] = "qffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\ 187 | fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\ 188 | fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffj" 189 | .as_bytes(); 190 | let unpacked = unpack_pill(pill.to_vec()).expect("Pill unpack failed"); 191 | assert_eq!(noun, unpacked); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------