Getting the pieces that make up an `std::fmt::Arguments` instance? - rust

When I have an Arguments instance, is it possible to read the parts that make it up?
It seems like the only thing I can do with it is pass it to format! and friends.
So in the example below, is it possible to read "{} hello {}", 1 and 2?
The reason I ask is that I want to implement a custom fern log format, and I want to determine if any of the strings are valid JSON so that they can go into a separate meta JSON key for JSON-lines logging. This way the JSON data does not need to parsed by the end user from the message.
https://doc.rust-lang.org/std/fmt/struct.Arguments.html
let x: Arguments = format_args!("{} hello {}", 1, 2);
// Can I read back the parts from `x`?

No, Arguments does not expose its internals in a way that can be inspected.
And even if you could access the internals (as seen in the source), the elements are stored in a type-erased form, making it difficult to use beyond running it through its associated formatting function.

Related

gcloud translate submitting lists

The codelab example for using gcloud translate via python only translates one string:
sample_text = "Hello world!"
target_language_code = "tr"
response = client.translate_text(
contents=[sample_text],
target_language_code=target_language_code,
parent=parent,
)
for translation in response.translations:
print(translation.translated_text)
But since it puts sample_text in a list and iterates over the response, I take it one can submit a longer list. Is this true and can I count on the items in the response corresponding to the order of items in contents? This must be the case but I can't find a clear answer in the docs.
translate_text contents is a Sequence[str] but must be less than 30k (codepoints).
For longer than 30k, use batch_translate_text
APIs Explorer provides an explanation of the request and response types for the translateText method. This allows you to call the underlying REST API method and it generates a 'form' for you in which content is an array of string (as expected).
The TranslateTextResponse describes translations as having the same length as contents.
There's no obvious other way to map entries in contents with translations so these must be in the same order, translations[foo] being the translation of contents[foo].
You can prove this to yourself by:
making the call with multiple known translations
including one word not in the source language (i.e. notknowninenglish in English) to confirm the translation result.

Dynamically generating arguments Clap

I'm trying to figure out how to dynamically generating arguments from input arguments with Clap.
What I'm trying to emulate with Clap is the following python code:
parser = argparse.ArgumentParser()
parser.add_argument("-i", type=str, nargs="*")
(input_args, additional_args) = parser.parse_known_args()
for arg in input_args:
parser.add_argument(f'--{arg}-bar', required=true, type=str)
additional_config = parser.parse_args(additional_args)
So that you can do the following in your command:
./foo.py -i foo bar baz --foo-bar foo --bar-bar bar --baz-bar bar
and have the additional arguments be dynamically generated from the first arguments. Not sure if it's possible to do in Clap but I assumed it was maybe possible due to the Readme stating you could use the builder pattern to dynamically generate arguments[1].
So here is my naive attempt of trying to do this.
use clap::{Arg, App};
fn main() {
let mut app = App::new("foo")
.arg(Arg::new("input")
.short('i')
.value_name("INPUT")
.multiple(true)
.required(true));
let matches = app.get_matches_mut();
let input: Vec<_> = matches.values_of("input").unwrap().collect()
for i in input {
app.arg(Arg::new(&*format!("{}-bar", i)).required(true))
}
}
Which does not obviously having the compiler scream at you for both !format lifetime and app.arg I'm mostly interesting in solving how I could generate new arguments to the app which then could be matched against again. I'm quite new to rust so it's quite possible this is not possible with Clap.
[1] https://github.com/clap-rs/clap
I assumed it was maybe possible due to the Readme stating you could use the builder pattern to dynamically generate arguments[1].
Dynamically generating argument means that, you can .arg with runtime values and it'll work fine (aka the entire CLI doesn't need to be fully defined at compile-time, this distinction doesn't exist in Python as everything is done at runtime).
What you're doing here is significantly more complicated (and specialised, and odd) as you're passing through unknown parameters then re-parsing them.
Now first of all, you literally can't reuse App in clap: most of its methods (very much including get_matches) take self and therefore "consume" the App and return something else, either the original App or a result. Although you can clone the original App before you get_matches it I guess.
But I don't think that's useful here: though I have not tried it should be possible do do what you want using TrailingVarArg: this would collect all trailing arguments into a single positional arg slice (you will probably need AllowLeadingHyphen as well), then you can create a second App with dynamically generated parameters in order to parse that sub-set of arguments (get_matches_from will parse from an iterator rather than the env args, this is useful for testing... or for this exact sort of situations).

Writing a raw binary structure to file in D?

I'm trying to have a binary file which contains several binary records defined in some struct. However, I do cannot seem to find how to do it. Looking at other examples, I've managed to write strings without problems, but not struct. I just want to write it like I would in C with fwrite(3), but in D version 2.
Here is what I've tried so far:
using stream.write(tr) - writes human readable/debug representation
using stream.rawWrite(tr) - this sounded like what I need, but fails to compile with:
Error: template std.stdio.File.rawWrite cannot deduce function from
argument types !()(TitleRecord), candidates are:
/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d(1132): std.stdio.File.rawWrite(T)(in T[] buffer)
trying rawWrite as above, but casting data to various things, also never compiles.
even trying to get back to C with fwrite, but can't get deep enough to get file descriptor I need.
Reading the docs has not been very helpful (writing strings works for me too, but not writing struct). I'm sure there must be simple way to do it, but I'm not able to find it.... Other SO questions did not help me. I D 1.0, it might have been accomplished with stream.writeExact(&tr, tr.sizeof) but that is no longer an option.
import std.stdio;
struct TitleRecord {
short id;
char[49] text;
};
TitleRecord tr;
void main()
{
auto stream = File("filename.dat","wb+");
tr.id = 1234;
tr.text = "hello world";
writeln(tr);
//stream.write(tr);
//stream.rawWrite(tr);
//stream.rawWrite(cast(ubyte[52]) tr);
//stream.rawWrite(cast(ubyte[]) tr);
//fwrite(&tr, 4, 1, stream);
}
For this that error is saying it expects an array not a struct. So one easy way to do it is to simply slice a pointer and give that to rawWrite:
stream.rawWrite((&tr)[0 .. 1]);
The (&tr) gets the address, thus converting your struct to a pointer. Then the [0 .. 1] means get a slice of it from the beginning, grabbing just one element.
Thus you now have a T[] that rawWrite can handle containing your one element.
Be warned if you use the #safe annotation this will not pass, you'd have to mark it #trusted. Also of course any references inside your struct (including string) will be written as binary pointers instead of data as you surely know from C experience. But in the case you showed there you're fine.
edit: BTW you could also just use fwrite if you like, copy/pasting the same code over from C (except it is foo.sizeof instead of sizeof foo). The D File thing is just a small wrapper around C's FILE* and you can get the original FILE* back out to pass to the other functions with stream.getFP() http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html )
rawWrite expects an array, but there are many workarounds.
One is to create a single element array.
file.rawWrite([myStruct]);
Another one is casting the struct into an array. My library called bitleveld has a function for that called reinterpretAsArray. This also makes it easy to create checksums of said structs.
Once in a while I've encountered issues with alignment using this method, so be careful. Could be fixed by changing the align property of the struct.

Get BuiltInParameterId from BuiltIn Parameter ElementId in Revit

Is there a Way to get the BuiltInParameterId (Ex:BuiltInParameter.SHEET_SIZE)
from a Parameter ElementId.
I have a number extracted from an Schedule Field (-1010106)
and I want to get the BuildInParameter-id.
Currently I am doing it like this:
BIPdic = {i.value__ : i for i in BuiltInParameter.GetValues(BuiltInParameter)}
bipid= BIPdic[-1010106]
I could not find an easier way. (Its easy, but I have to built a dictionary
from all (over 3000 BuiltInParameters)).
THX
tillbaum
I am not absolutely sure I know what you mean. Check out the description of the ElementId constructor taking a BuiltInParameter input argument.
You can also take a look at the built-in parameter checker BipChecker and its BipChecker GitHub repo. It iterates over all built-in parameter values and tries to retrieve a parameter value for each one.
That sounds pretty similar to what you are after with your dictionary.

How to make this Groovy string search code more efficient?

I'm using the following groovy code to search a file for a string, an account number. The file I'm reading is about 30MB and contains 80,000-120,000 lines. Is there a more efficient way to find a record in a file that contains the given AcctNum? I'm a novice, so I don't know which area to investigate, the toList() or the for-loop. Thanks!
AcctNum = 1234567890
if (testfile.exists())
{
lines = testfile.readLines()
words = lines.toList()
for (word in words)
{
if (word.contains(AcctNum)) { done = true; match = 'YES' ; break }
chunks += 1
if (done) { break }
}
}
Sad to say, I don't even have Groovy installed on my current laptop - but I wouldn't expect you to have to call toList() at all. I'd also hope you could express the condition in a closure, but I'll have to refer to Groovy in Action to check...
Having said that, do you really need it split into lines? Could you just read the whole thing using getText() and then just use a single call to contains()?
EDIT: Okay, if you need to find the actual line containing the record, you do need to call readLines() but I don't think you need to call toList() afterwards. You should be able to just use:
for (line in lines)
{
if (line.contains(AcctNum))
{
// Grab the results you need here
break;
}
}
When you say efficient you usually have to decide which direction you mean: whether it should run quickly, or use as few resources (memory, ...) as possible. Often both lie on opposite sites and you have to pick a trade-off.
If you want to search memory-friendly I'd suggest reading the file line-by-line instead of reading it at once which I suspect it does (I would be wrong there, but in other languages something like readLines reads the whole file into an array of strings).
If you want it to run quickly I'd suggest, as already mentioned, reading in the whole file at once and looking for the given pattern. Instead of just checking with contains you could use indexOf to get the position and then read the record as needed from that position.
I should have explained it better, if I find a record with the AcctNum, I extract out other information on the record...so I thought I needed to split the file into multiple lines.
if you control the format of the file you are reading, the solution is to add in an index.
In fact, this is how databases are able to locate records so quickly.
But for 30MB of data, i think a modern computer with a decent harddrive should do the trick, instead of over complicating the program.

Resources