Last active
August 29, 2015 14:07
-
-
Save pythonesque/87bc4a7299ef1f749b6e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub mod bitmap { | |
pub type ColorComponent = u8; | |
#[deriving(Clone, Default, Eq, PartialEq)] | |
pub struct Pixel { | |
pub r: ColorComponent, | |
pub g: ColorComponent, | |
pub b: ColorComponent, | |
} | |
pub static BLACK: Pixel = Pixel { r: ::std::u8::MIN, g: ::std::u8::MIN, b: ::std::u8::MIN }; | |
pub static WHITE: Pixel = Pixel { r: ::std::u8::MAX, g: ::std::u8::MAX, b: ::std::u8::MAX }; | |
#[deriving(Clone)] | |
pub struct Image<T> { | |
width: uint, | |
height: uint, | |
buf: Vec<T>, | |
} | |
#[deriving(Clone, Eq, PartialEq)] | |
pub enum ImageError { | |
DimensionError, | |
} | |
pub trait Color: PartialEq { | |
fn black() -> Self; | |
fn white() -> Self; | |
fn is_black(&self) -> bool { *self == Color::black() } | |
fn is_white(&self) -> bool { *self == Color::white() } | |
} | |
impl Pixel { | |
pub fn new(r: ColorComponent, g: ColorComponent, b: ColorComponent) -> Pixel { | |
Pixel { r: r, g: g, b: b } | |
} | |
} | |
impl Color for Pixel { | |
fn black() -> Pixel { BLACK } | |
fn white() -> Pixel { WHITE } | |
} | |
impl<T: Copy + Color> Image<T> { | |
pub unsafe fn alloc(width: uint, height: uint) -> Result<Image<T>, ImageError> { | |
match width.checked_mul(&height) { | |
Some(s) => Ok(Image { | |
width: width, | |
height: height, | |
buf: { | |
let mut buf = Vec::with_capacity(s); | |
buf.set_len(s); | |
buf | |
}, | |
}), | |
None => return Err(DimensionError) | |
} | |
} | |
pub fn from_data(data: Vec<T>, width: uint, height: uint) -> Result<Image<T>, ImageError> { | |
match width.checked_mul(&height) { | |
Some(s) if s == data.len() => Ok(Image { | |
width: width, | |
height: height, | |
buf: data, | |
}), | |
_ => { return Err(DimensionError) } | |
} | |
} | |
pub fn width(&self) -> uint { self.width } | |
pub fn height(&self) -> uint { self.height } | |
pub fn get(&self, x: uint, y: uint) -> Option<&T> { | |
if self.width <= x || self.height <= y { | |
None | |
} else { | |
let ref c = self.buf[y * self.width + x]; | |
Some(c) | |
} | |
} | |
pub fn get_mut(&mut self, x: uint, y: uint) -> Option<&mut T> { | |
if self.width <= x || self.height <= y { | |
None | |
} else { | |
Some(self.buf.get_mut(y * self.width + x)) | |
} | |
} | |
pub fn clear(&mut self, color: T) { | |
for c in self.buf.iter_mut() { | |
*c = color; | |
} | |
} | |
} | |
/*pub trait ImageEncoder<T, E> { | |
pub fn emit_pixel(&mut self, T) -> Result<T, E>; | |
pub fn emit_image(&mut self, Image<T>) -> Result<T, E>; | |
} | |
pub trait Encodable<S: Encoder<E>, E> { | |
fn encode(&self, s: &mut S) -> Result<(), E>; | |
}*/ | |
} | |
module | |
pub fn main() { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(unboxed_closures,slicing_syntax)] | |
use std::io; | |
#[deriving(Show)] | |
enum Token<'a> { | |
Equals, | |
VBar, | |
LParen, RParen, | |
LBracket, RBracket, | |
LBrace, RBrace, | |
Semi, | |
Literal(&'a [Ascii]), | |
Ident(&'a [Ascii]), | |
EOF, | |
} | |
#[deriving(PartialEq,Show)] | |
enum Error { | |
UnterminatedStringLiteral, // Missing an end double quote during string parsing | |
IoError(io::IoError), // Some other kind of I/O error | |
IncorrectCloseDelimiter, // ) appeared where it shouldn't (usually as the first token) | |
UnexpectedEOF, // Usually means a missing ), but could also mean there were no tokens at all. | |
ExpectedEOF, // More tokens after the list is finished, or after a literal if there is no list. | |
} | |
struct Tokens<'a> { | |
string: &'a [Ascii], | |
first: Option<Ascii>, | |
rest: &'a [Ascii], | |
} | |
impl<'a> Tokens<'a> { | |
fn new(string: &'a [Ascii]) -> Tokens { | |
let (ch, s) = if string.len() == 0 { (None, string) } else { | |
let (ch, s) = string.split_at(1); | |
(ch.iter().map(|&ch| ch).next(), s) | |
}; | |
Tokens { string: string, first: ch, rest: s } | |
} | |
// Utility function to update information in the iterator. It might not be performant to keep | |
// rest cached, but there are times where we don't know exactly what string is (at least, not | |
// in a way that we can *safely* reconstruct it without allocating), so we keep both here. | |
// With some unsafe code we could probably get rid of one of them (and maybe first, too). | |
fn update(&mut self, string: &'a [Ascii]) { | |
self.string = string; | |
let (ch, s) = if string.len() == 0 { (None, string) } else { | |
let (ch, s) = string.split_at(1); | |
(ch.iter().map(|&ch| ch).next(), s) | |
}; | |
self.first = ch; | |
self.rest = s; | |
} | |
// This is where the lexing happens. Note that it does not handle string escaping. | |
fn next(&mut self) -> Result<Token<'a>, Error> { | |
loop { | |
match self.first.map ( |ch| ch.to_byte() ) { | |
// Equals | |
Some(b'=') => { | |
self.update(self.rest); | |
return Ok(Equals) | |
}, | |
Some(b'|') => { | |
self.update(self.rest); | |
return Ok(VBar) | |
} | |
// ( start | |
Some(b'(') => { | |
self.update(self.rest); | |
return Ok(LParen) | |
}, | |
// ) end | |
Some(b')') => { | |
self.update(self.rest); | |
return Ok(RParen) | |
}, | |
// [ start | |
Some(b'[') => { | |
self.update(self.rest); | |
return Ok(LBracket) | |
}, | |
// ] end | |
Some(b']') => { | |
self.update(self.rest); | |
return Ok(RBracket) | |
}, | |
// { start | |
Some(b'{') => { | |
self.update(self.rest); | |
return Ok(LBrace) | |
}, | |
// } end | |
Some(b'}') => { | |
self.update(self.rest); | |
return Ok(RBrace) | |
}, | |
// . or ; | |
Some(b'.') | Some(b';') => { | |
self.update(self.rest); | |
return Ok(Semi) | |
}, | |
// Double quoted literal start | |
Some(b'"') => { | |
// Split the string at most once. This lets us get a | |
// reference to the next piece of the string without having | |
// to loop through the string again. | |
let mut iter = self.rest.splitn(1, |&ch| ch == b'"'.to_ascii()); | |
// The first time splitn is run it will never return None, so this is safe. | |
let str = iter.next().unwrap(); | |
match iter.next() { | |
// Extract the interior of the string without allocating. If we want to | |
// handle string escaping, we would have to allocate at some point though. | |
Some(s) => { | |
self.update(s); | |
return Ok(Literal(str)) | |
}, | |
None => return Err(UnterminatedStringLiteral) | |
} | |
}, | |
// Single quoted literal start | |
Some(b'\'') => { | |
// Split the string at most once. This lets us get a | |
// reference to the next piece of the string without having | |
// to loop through the string again. | |
let mut iter = self.rest.splitn(1, |&ch| ch == b'\''.to_ascii()); | |
// The first time splitn is run it will never return None, so this is safe. | |
let str = iter.next().unwrap(); | |
match iter.next() { | |
// Extract the interior of the string without allocating. If we want to | |
// handle string escaping, we would have to allocate at some point though. | |
Some(s) => { | |
self.update(s); | |
return Ok(Literal(str)) | |
}, | |
None => return Err(UnterminatedStringLiteral) | |
} | |
}, | |
// Identifier start | |
Some(c) => { | |
// Skip whitespace. This could probably be made more efficient. | |
match c { | |
b' ' | b'\x09' ... b'\x0d' => { | |
self.update(self.rest); | |
continue | |
}, | |
_ => (), | |
} | |
// Since we've exhausted all other possibilities, this must be a real identifier. | |
// Unlike the quoted case, it's not an error to encounter EOF before whitespace. | |
let mut end_ch = None; | |
let mut len = 0; | |
let str = { | |
let mut iter = self.string.iter(); | |
let str; | |
loop { | |
let ch = iter.next(); | |
match ch { | |
Some(ch) => { | |
len += 1; | |
let term = match ch.to_byte() { | |
b'=' | b'|' | b'(' | b')' | b'{' | b'}' | b'[' | b']' | b'.' | b';' | b'"' | b'\'' => true, | |
_ => false | |
}; | |
if term { end_ch = Some(ch); } | |
if term || (match ch.to_byte() { b' ' | b'\x09' ... b'\x0d' => true, _ => false }) { | |
str = self.string[.. len - 1]; | |
self.rest = self.string[len - 1 .. ]; | |
break; | |
} | |
}, | |
None => { | |
str = self.string; | |
self.rest = "".to_ascii(); | |
break | |
} | |
} | |
}; | |
str | |
}; | |
match end_ch { | |
// self.string will be incorrect in the Some(_) case. The only reason it's | |
// okay is because the next time next() is called in this case, we know it | |
// will be '(' or ')', so it will never reach any code that actually looks | |
// at self.string. In a real implementation this would be enforced by | |
// visibility rules. | |
Some(c) => self.first = Some(*c), | |
None => self.update(self.rest) | |
} | |
return Ok(Ident(str)); | |
} | |
None => return Ok(EOF) | |
} | |
} | |
} | |
} | |
fn parse(string: &[Ascii]) -> Result<(), Error> { | |
let mut tokens = Tokens::new(string); | |
loop { | |
let tok = tokens.next(); | |
match try!(tok) { | |
EOF => return Ok(()), | |
Ident(s) => println!("Ident({})", s.as_str_ascii()), | |
Literal(s) => println!("Literal({})", s.as_str_ascii()), | |
t => println!("{}", t), | |
} | |
} | |
} | |
fn main() { | |
const EBNF: &'static [u8] = br#" | |
"EBNF defined in itself" { | |
syntax = [ title ] "{" { production } "}" [ comment ]. | |
production = identifier "=" expression ( "." | ";" ) . | |
expression = term { "|" term } . | |
term = factor { factor } . | |
factor = identifier | |
| literal | |
| "[" expression "]" | |
| "(" expression ")" | |
| "{" expression "}" . | |
identifier = character { character } . | |
title = literal . | |
comment = literal . | |
literal = "'" character { character } "'" | |
| '"' character { character } '"' . | |
}"#; | |
let ebnf_ascii = EBNF.to_ascii(); | |
parse(ebnf_ascii).unwrap(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(tuple_indexing)] | |
extern crate time; | |
use std::default::Default; | |
use std::f32::consts::PI; | |
use std::num::{Zero, zero}; | |
use std::sync::{Arc, Mutex}; | |
use std::time::duration::Duration; | |
use std::io::timer::Timer; | |
use time::precise_time_ns; | |
#[deriving(Clone, Default)] | |
pub struct Ratio<T, U>(T, U); | |
pub struct Area(f32); | |
impl Mul<Duration, Area> for | |
impl Mul<Duration, f32> for Ratio<f32, Duration> { | |
fn mul(&self, rhs: &Duration) -> f32 { | |
self.1 * (rhs.num_nanoseconds() / self.0.num_nanoseconds()) as f32 | |
} | |
} | |
/*impl<T, U: Div<V, U>, V> Mul<V, T> for Ratio<T, U> { | |
pub fn mul(&self, rhs: &V) -> T { | |
} | |
}*/ | |
//pub struct Integrator<S: Zero, K: Fn<Duration, S>> { | |
pub struct Integrator<S: Send, T: Send> { | |
input: Sender<|Duration|: Send -> S>, | |
output: Arc<Mutex<T>>, | |
} | |
impl<S: Default + Mul<Duration, T> + Send + Zero, | |
T: Clone + Send + Sync + Zero> Integrator<S, T> { | |
pub fn new(frequency: Duration) -> Integrator<S, T> { | |
let (tx, input) = channel(); | |
let integrator = Integrator { | |
input: tx, | |
output: Arc::new(Mutex::new(zero::<T>())), | |
}; | |
let s = integrator.output.clone(); | |
spawn(proc() { | |
let mut timer = match Timer::new() { | |
Ok(timer) => timer, | |
Err(_) => return | |
}; | |
let periodic = timer.periodic(frequency); | |
let mut t = Duration::nanoseconds(precise_time_ns() as i64); | |
let mut k = |t| Default::default(); | |
let mut k_0: S = Default::default(); | |
loop { | |
select! { | |
res = periodic.recv_opt() => match res { | |
Ok(_) => { | |
t = t + frequency; | |
let k_1: S = k(t); | |
let mut s = s.lock(); | |
*s = *s + (k_1 * (frequency / 2) + k_0 * (frequency / 2)); | |
} | |
Err(_) => break, | |
}, | |
res = input.recv_opt() => match res { | |
Ok(k_new) => k = k_new, | |
Err(_) => break, | |
} | |
} | |
} | |
}); | |
integrator | |
} | |
pub fn input(&self, k: |Duration|: Send -> S) -> Result<(), |Duration|: Send -> S> { | |
self.input.send_opt(k) | |
} | |
pub fn output(&self) -> T { self.output.lock().clone() } | |
} | |
fn main() { | |
let f = 1 / Duration::seconds(2).num_milliseconds() as f32; | |
let object = Integrator::new(Duration::milliseconds(10)); | |
object.input(|t| (PI * 2. * f * t.num_milliseconds()).sin()).unwrap(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[allow(dead_code)] | |
pub mod ldap { | |
use self::protocol as p; | |
use std::collections::HashSet; | |
mod protocol { | |
use ldap as l; | |
use std::collections::HashSet; | |
// 4.2. Bind Operation | |
pub struct BindRequest { | |
version: i8, | |
name: l::LdapDN, | |
authentication: AuthenticationChoice, | |
} | |
enum AuthenticationChoice { | |
Simple(Vec<u8>), | |
Sasl(SaslCredentials), | |
} | |
struct SaslCredentials { | |
mechanism: l::LdapString, | |
credentials: Option<Vec<u8>>, | |
} | |
// 4.2.2. Bind Response | |
pub struct BindResponse { | |
ldap_result: l::LdapResult, | |
server_sasl_creds: Option<Vec<u8>>, | |
} | |
// 4.3. Unbind Operation | |
pub struct UnbindRequest; | |
// 4.5. Search Operation | |
// 4.5.1. Search Request | |
pub struct SearchRequest { | |
base_object: l::LdapDN, | |
scope: SearchRequestScope, | |
deref_aliases: SearchRequestDerefAliases, | |
size_limit: l::Integer, | |
time_limit: l::Integer, | |
types_only: bool, | |
filter: Filter, | |
attributes: AttributeSelection, | |
} | |
// 4.5.1.2. SearchRequest.scope | |
#[deriving(FromPrimitive)] | |
enum SearchRequestScope { | |
BaseObject = 0, | |
SingleLevel = 1, | |
WholeSubTree = 2, | |
} | |
// 4.5.1.3. SearchRequest.derefAliases | |
#[deriving(FromPrimitive)] | |
enum SearchRequestDerefAliases { | |
NeverDerefAliases = 0, | |
DerefInSearching = 1, | |
DerefFindingBaseObj = 2, | |
DerefAlways = 3, | |
} | |
// 4.5.1.7. SearchRequest.filter | |
enum Filter { | |
And(HashSet<Filter>), | |
Or(HashSet<Filter>), | |
Not(Box<Filter>), | |
EqualityMatch(l::AttributeValueAssertion), | |
Substrings(SubstringFilter), | |
GreaterOrEqual(l::AttributeValueAssertion), | |
LessOrEqual(l::AttributeValueAssertion), | |
Present(l::AttributeDescription), | |
ApproxMatch(l::AttributeValueAssertion), | |
ExtensibleMatch(MatchingRuleAssertion), | |
} | |
// 4.5.1.7.2. SearchRequest.filter.substrings | |
struct SubstringFilter { | |
ty: l::AttributeDescription, | |
substrings: Vec<Substring> | |
} | |
enum Substring { | |
Initial(l::AssertionValue), | |
Any(l::AssertionValue), | |
Final(l::AssertionValue), | |
} | |
// 4.5.1.7.7. SearchRequest.filter.extensibleMatch | |
struct MatchingRuleAssertion { | |
matching_rule: Option<l::MatchingRuleId>, | |
ty: Option<l::AttributeDescription>, | |
match_value: l::AssertionValue, | |
dn_attributes: bool, | |
} | |
// 4.5.1.8. SearchRequest.attributes | |
struct AttributeSelection(Vec<l::LdapString>); | |
// 4.5.2. Search Result | |
pub struct SearchResultEntry { | |
object_name: l::LdapDN, | |
attributes: PartialAttributeList, | |
} | |
struct PartialAttributeList(Vec<l::PartialAttribute>); | |
pub struct SearchResultReference(Vec<l::URI>); | |
pub struct SearchResultDone(l::LdapResult); | |
// 4.6. Modify Operation | |
pub struct ModifyRequest { | |
object: l::LdapDN, | |
changes: Vec<Change>, | |
} | |
struct Change { | |
operation: ChangeOperation, | |
modification: l::PartialAttribute, | |
} | |
#[deriving(FromPrimitive)] | |
enum ChangeOperation { | |
Add = 0, | |
Delete = 1, | |
Replace = 2, | |
} | |
pub struct ModifyResponse(l::LdapResult); | |
// 4.7. Add Operation | |
pub struct AddRequest { | |
entry: l::LdapDN, | |
attributes: AttributeList, | |
} | |
struct AttributeList(Vec<l::Attribute>); | |
pub struct AddResponse(l::LdapResult); | |
// 4.8. Delete Operation | |
pub struct DelRequest(l::LdapDN); | |
pub struct DelResponse(l::LdapResult); | |
// 4.9. Modify DN Operation | |
pub struct ModifyDNRequest { | |
entry: l::LdapDN, | |
newrdn: l::RelativeLdapDN, | |
deleteoldrdn: bool, | |
new_superior: Option<l::LdapDN>, | |
} | |
pub struct ModifyDNResponse(l::LdapResult); | |
// 4.10. Compare Operation | |
pub struct CompareRequest { | |
entry: l::LdapDN, | |
ava: l::AttributeValueAssertion, | |
} | |
pub struct CompareResponse(l::LdapResult); | |
// 4.11. Abandon Operation | |
pub struct AbandonRequest(l::MessageID); | |
// 4.12. Extended Operation | |
pub struct ExtendedRequest { | |
request_name: l::LdapOid, | |
request_value: Option<Vec<u8>>, | |
} | |
pub struct ExtendedResponse { | |
ldap_result: l::LdapResult, | |
response_name: Option<l::LdapOid>, | |
response_value: Option<Vec<u8>>, | |
} | |
// 4.13. Intermediate Response | |
pub struct IntermediateResponse { | |
response_name: Option<l::LdapOid>, | |
response_value: Option<Vec<u8>>, | |
} | |
// Appendix A. LDAP Result Codes | |
// A.2. Result Codes | |
#[deriving(FromPrimitive)] | |
pub enum LdapResultCode { | |
Success = 0, | |
OperationsError = 1, | |
ProtocoLError = 2, | |
TimeLimitExceeded = 3, | |
SizeLimitExceeded = 4, | |
CompareFalse = 5, | |
CompareTrue = 6, | |
AuthMethodNotSupported = 7, | |
StrongerAuthRequired = 8, | |
// 9 reserved | |
Referral = 10, | |
AdminLimitExceeded = 11, | |
UnavailableCriticalExtension = 12, | |
ConfidentialityRequired = 13, | |
SaslBindInProgress = 14, | |
NoSuchAttribute = 16, | |
UndefinedAttributeType = 17, | |
InappropriateMatching = 18, | |
ConstraintViolation = 19, | |
AttributeOrValueExists = 20, | |
InvalidAttributeSyntax = 21, | |
// 22-31 unused | |
NoSuchObject = 32, | |
AliasProblem = 33, | |
InvalidDNSSyntax = 34, | |
// 35 reserved for undefined isLeaf | |
AliasDereferencingProblem = 36, | |
// 37-47 unused | |
InappropriateAuthentication = 48, | |
InvalidCredentials = 49, | |
InsufficientAccessRights = 50, | |
Busy = 51, | |
Unvailable = 52, | |
UnwillingToPerform = 53, | |
LoopDetect = 54, | |
// 55-63 unused | |
NamingViolation = 64, | |
ObjectClassViolation = 65, | |
NotAllowedOnNonLeaf = 66, | |
NotAllowedOnRDN = 67, | |
EntryAlreadyExists = 68, | |
ObjectClassModsProhibited = 69, | |
// 70 reserved for CLDAP | |
AffectsMultipleDSAs = 71, | |
// 72-79 unused | |
Other = 80, | |
} | |
} | |
// 4.1. Common Elements | |
// 4.1.1. Message Envelope | |
pub struct LdapMessage { | |
message_id: MessageID, | |
protocol_op: LdapMessageProtocolOp, | |
controls: Controls, | |
} | |
enum LdapMessageProtocolOp { | |
BindRequest(p::BindRequest), | |
BindResponse(p::BindResponse), | |
UnbindRequest(p::UnbindRequest), | |
SearchRequest(p::SearchRequest), | |
SearchResEntry(p::SearchResultEntry), | |
SearchResDone(p::SearchResultDone), | |
SearchResRef(p::SearchResultReference), | |
ModifyRequest(p::ModifyRequest), | |
ModifyResponse(p::ModifyResponse), | |
AddRequest(p::AddRequest), | |
AddResponse(p::AddResponse), | |
DelRequest(p::DelRequest), | |
DelResponse(p::DelResponse), | |
ModDNRequest(p::ModifyDNRequest), | |
ModDNResponse(p::ModifyDNResponse), | |
CompareRequest(p::CompareRequest), | |
CompareResponse(p::CompareResponse), | |
AbandonRequest(p::AbandonRequest), | |
ExtendedReq(p::ExtendedRequest), | |
ExtendedResp(p::ExtendedResponse), | |
IntermediateResponse(p::IntermediateResponse), | |
} | |
type Integer = u32; | |
// 4.1.1.1. MessageID | |
struct MessageID(Integer); | |
// 4.1.2. String Types | |
type LdapString = String; | |
struct LdapOid(String); | |
// 4.1.3. Distinguished Name and Relative Distinguished Name | |
struct LdapDN(LdapString); | |
struct RelativeLdapDN(LdapString); | |
// 4.1.4. Attribute Descriptions | |
struct AttributeDescription(LdapString); | |
// 4.1.5. Attribute Value | |
struct AttributeValue(String); | |
// 4.1.6. Attribute Value Assertion | |
struct AttributeValueAssertion { | |
attribute_desc: AttributeDescription, | |
assertion_value: AssertionValue, | |
} | |
struct AssertionValue(Vec<u8>); | |
// 4.1.7. Attribute and PartialAttribute | |
struct PartialAttribute { | |
ty: AttributeDescription, | |
vals: HashSet<AttributeValue>, | |
} | |
struct Attribute(PartialAttribute); | |
// 4.1.8. Matching Rule Identifier | |
struct MatchingRuleId(LdapString); | |
// 4.1.9. LdapResult | |
struct LdapResult { | |
result_code: p::LdapResultCode, | |
matched_dn: LdapDN, | |
diagnostic_message: LdapString, | |
referral: Option<Referral>, | |
} | |
// 4.1.10. Referral | |
struct Referral(Vec<URI>); | |
struct URI(LdapString); | |
// 4.1.11. Controls | |
struct Controls(Vec<Control>); | |
struct Control { | |
control_type: LdapOid, | |
criticality: bool, | |
control_value: Option<Vec<u8>>, | |
} | |
} | |
fn main() { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment