I have the following test:
pub(crate) fn from_byte_slice(packet: &[u8]) -> BackendKeyData {
let mut backend = BackendKeyData::new();
backend.pid = i32::from_be_bytes(pop(&packet[5..9]));
backend.key = i32::from_be_bytes(pop(&packet[9..]));
backend
}
#[test]
fn test_backend_key_data() {
let bytes = b"\x75\x00\x00\x00\x12\x00\x00\x149\x241\x17\x173\x241\x137";
let backend = BackendKeyData::from_byte_slice(bytes);
assert_eq!(backend.pid, 0);
}
When I debug the test the byte array changes and becomes this slice:
[0]:117
[1]:0
[2]:0
[3]:0
[4]:18
[5]:0
[6]:0
[7]:20
[8]:57
[9]:36
[10]:49
[11]:23
[12]:23
[13]:51
[14]:36
[15]:49
[16]:19
[17]:55
What's going on here, why the change?
\x is for 2 digit hexadecimal escapes only. \x137 does not make a byte with value 137, but instead a byte with value 0x13 followed by the byte represented by the ascii character 7. Use an array literal for base 10 values instead:
&[75, 0, 0, 0, 12, 0, 0, 149, 241, 17, 173, 241, 137]
Related
I have gotten this neat way of padding vector messages, such that I can know that they will be the same length
let len = 20;
let mut msg = vec![1, 23, 34];
msg.resize(len, 0);
println!("msg {:?}", msg);
Nice, this pads a lot of zeros to any message, running this code will give me:
msg [1, 23, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
But let's say I send this message over some connection, and the other party receives it at their end.
How do I take a vector like this, and strip off all the 0's in the end?
Notice that the length of the original message may be of variable length, but always less than 20
Another thing that could work for me, is to have all the padding at the beginning of the vector, doing something like this:
let len = 20;
let msg = vec![1, 23, 34];
let mut payload = vec![0;len-msg.len()];
payload.extend(&msg);
println!("msg {:?}", payload);
And then just removing, all the preleading zero's.
As stated in the comments above, probably changing your protocol to include the length of the message is cleaner.
But here would be the solution to remove padding in front of the message (if the message doesn't start with zeros):
let msg: Vec<_> = payload.into_iter().skip_while(|x| *x == 0).collect();
Note that this allocates a new Vec for your msg, probably you could use the iterator directly.
Playground
I've noticed that in Rust, we can't use the byte notation for values larger than 128, that is
let x = "\x01\x17\x7f"
is fine since all chars are < 128, but
let x = "\x01\x17\x80"
will fail since \x80 = 128.
Is there any way to still write string-like objects in that format?
Above 127 you enter the realm of Unicode and must use the \u{codepoint} escape sequence:
let x = "\u{80}";
Note however that 0x80 by itself isn't a valid byte in a UTF-8 string, so this turns out as two bytes:
let x = "\u{80}";
for b in x.bytes() {
println!("{:X}", b);
}
prints
C2
80
If you instead need the value 0x80, you can't use a string and must use a byte slice:
fn main() {
let x = b"\x80";
for b in x {
println!("{:X}", b);
}
}
prints
80
I have two arrays of values:
t = [0; 1; 2];
q = [0; 100; 200];
I need those to be one string that's like:
str = '0, 0, 1, 100, 2, 200';
I can't see a nice way to do it in MATLAB (R2017a) without using a loop. I'd like to avoid that if possible as there's a pretty large array of values and a lot of files and it'll take forever.
Any ideas?
Combine compose with strjoin:
t = [0; 1; 2];
q = [0; 100; 200];
str = strjoin(compose('%d', [t(:)'; q(:)']), ', ');
Output:
str =
'0, 0, 1, 100, 2, 200'
For non integer numbers, use: %f instead of %d
Here's a possible approach. This works for integer numbers, or if you want a fixed number of decimals in the string representation:
t = [0; 1; 2];
q = [0; 100; 200];
tq = reshape([t(:).'; q(:).'], 1, []);
s = sprintf('%i, ',tq); % or change '%i' to something like '%.5f'
s = s(1:end-2)
Result:
s =
'0, 0, 1, 100, 2, 200'
If you have non-integer numbers and want the number of decimals in the representation to be chosen automatically, you can use mat2str instead of sprintf, but then you need to deal with the spaces using regexpre or a similar function:
t = [0; 1; 2];
q = [0; 100; 200];
tq = reshape([t(:).'; q(:).'], 1, [])
s = regexprep(num2str(tq), '\s+', ', ');
I am stumped as to how to use the PgNumeric type for decimal numbers. I noticed in the tests that 1.0 and -31.0 were inserted into a table using the following instances:
PgNumeric::Positive { weight: 0, scale: 1, digits: vec![1] }
and
PgNumeric::Negative {weight: 0, scale: 1, digits: vec![31] }
I can't seem to figure out how to insert a value with digits to the right of the decimal (like 5.4321) into a table.
Short answer: PgNumeric::Positive { weight: 0, scale: 4, digits: [5, 4321] }
More examples:
// 9.87654321::numeric
PgNumeric::Positive { weight: 0, scale: 8, digits: [9, 8765, 4321] }
// 12345.6789::numeric
PgNumeric::Positive { weight: 1, scale: 4, digits: [1, 2345, 6789] }
// 100000000.000000002::numeric
PgNumeric::Positive { weight: 2, scale: 9, digits: [1, 0, 0, 0, 0, 2000] }
// 0.3::numeric
PgNumeric::Positive { weight: -1, scale: 1, digits: [3000] }
It looks as if the algorithm is:
Group your number into chunks of 4 digits starting at the decimal point and working outward. These are the digits.
Count the number of chunks needed to represent the integral part and subtract one. This is the weight.
Count the number of digits needed to represent the fractional part. This is the scale.
Test harness
Here's the code I am playing with, extracted from the tests:
extern crate diesel;
use diesel::*;
use diesel::types::*;
use diesel::pg::data_types::PgNumeric;
use diesel::pg::PgConnection;
type PgBackend = <PgConnection as Connection>::Backend;
fn main() {
let query = "100000000.000000002::numeric";
let expected_value = PgNumeric::Negative {
digits: vec![31],
weight: 0,
scale: 1,
};
assert_eq!(expected_value, query_single_value::<Numeric, PgNumeric>(query));
}
fn query_single_value<T, U: Queryable<T, PgBackend>>(sql_str: &str) -> U
where PgBackend: HasSqlType<T>,
{
use diesel::expression::dsl::sql;
let connection = connection();
select(sql::<T>(sql_str)).first(&connection).unwrap()
}
fn connection() -> PgConnection {
let result = connection_without_transaction();
result.begin_test_transaction().unwrap();
result
}
fn connection_without_transaction() -> PgConnection {
let connection_url = "postgres://localhost/some_db";
::diesel::pg::PgConnection::establish(&connection_url).unwrap()
}
Potentially useful background information
From the Postgres docs:
The scale of a numeric is the count of decimal digits in the fractional part, to the right of the decimal point. The precision of a numeric is the total count of significant digits in the whole number, that is, the number of digits to both sides of the decimal point. So the number 23.5141 has a precision of 6 and a scale of 4.
However, the Postgres code says:
/*
* In the NumericShort format, the remaining 14 bits of the header word
* (n_short.n_header) are allocated as follows: 1 for sign (positive or
* negative), 6 for dynamic scale, and 7 for weight. In practice, most
* commonly-encountered values can be represented this way.
*
* In the NumericLong format, the remaining 14 bits of the header word
* (n_long.n_sign_dscale) represent the display scale; and the weight is
* stored separately in n_weight.
*/
I know there's a bunch of pre Swift3 questions regarding NSData stuff. I'm curious how to go between a Swift3 String to a utf8 encoded (with or without null termination) to Swift3 Data object.
The best I've come up with so far is:
let input = "Hello World"
let terminatedData = Data(bytes: Array(input.nulTerminatedUTF8))
let unterminatedData = Data(bytes: Array(input.utf8))
Having to do the intermediate Array() construction seems wrong.
It's simple:
let input = "Hello World"
let data = input.data(using: .utf8)!
If you want to terminate data with null, simply append a 0 to it. Or you may call cString(using:)
let cString = input.cString(using: .utf8)! // null-terminated
NSString methods from NSFoundation framework should be dropped in favor for Swift Standard Library equivalents. Data can be initialized with any Sequence which elements are UInt8. String.UTF8View satisfies this requirement.
let input = "Hello World"
let data = Data(input.utf8)
// [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
String null termination is an implementation detail of C language and it should not leak outside. If you are planning to work with C APIs, please take a look at the utf8CString property of String type:
public var utf8CString: ContiguousArray<CChar> { get }
Data can be obtained after CChar is converted to UInt8:
let input = "Hello World"
let data = Data(input.utf8CString.map { UInt8($0) })
// [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 0]