Can Rust macros create compile-time strings? - macros

Macro variables are escaped in Rust macros by default. Is there any way to have them not escaped?
macro_rules! some {
( $var:expr ) => ( "$var" );
}
some!(1) // returns "$var", not "1"
This is useful for concatenating compile-time strings and such.

It sounds like you want stringify!:
macro_rules! some {
( $var:expr ) => ( stringify!($var) );
}
fn main() {
let s = some!(1);
println!("{}", s);
}
And you will probably want concat! too.
See also:
How to create a static string at compile time

Related

Is Swift's handling of CVarArg for String buggy?

While writing a Swift wrapper for a C wrapper of a C++ library, I've stumbled on some weird bugs regarding Swift's CVarArg. The C wrapper I already have uses variadic functions which I converted to functions using va_list as an argument so they could be imported (since Swift cannot import C variadic functions). When passing arguments to such a function, once bridged to Swift, it uses the private _cVarArgEncoding property of types conforming to CVarArg to "encode" the values which are then sent as a pointer to the C function. It seems however that this encoding is faulty for Swift Strings.
To demonstrate, I've created the following package:
Package.swift
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "CVarArgTest",
products: [
.executable(
name: "CVarArgTest",
targets: ["CVarArgTest"]),
],
targets: [
.target(
name: "CLib"),
.target(
name: "CVarArgTest",
dependencies: ["CLib"])
]
)
CLib
CTest.h
#ifndef CTest_h
#define CTest_h
#include <stdio.h>
/// Prints out the strings provided in args
/// #param num The number of strings in `args`
/// #param args A `va_list` of strings
void test_va_arg_str(int num, va_list args);
/// Prints out the integers provided in args
/// #param num The number of integers in `args`
/// #param args A `va_list` of integers
void test_va_arg_int(int num, va_list args);
/// Just prints the string
/// #param str The string
void test_str_print(const char * str);
#endif /* CTest_h */
CTest.c
#include "CTest.h"
#include <stdarg.h>
void test_va_arg_str(int num, va_list args)
{
printf("Printing %i strings...\n", num);
for (int i = 0; i < num; i++) {
const char * str = va_arg(args, const char *);
puts(str);
}
}
void test_va_arg_int(int num, va_list args)
{
printf("Printing %i integers...\n", num);
for (int i = 0; i < num; i++) {
int foo = va_arg(args, int);
printf("%i\n", foo);
}
}
void test_str_print(const char * str)
{
puts(str);
}
main.swift
import Foundation
import CLib
// The literal String is perfectly bridged to the CChar pointer expected by the function
test_str_print("Hello, World!")
// Prints the integers as expected
let argsInt: [CVarArg] = [123, 456, 789]
withVaList(argsInt) { listPtr in
test_va_arg_int(Int32(argsInt.count), listPtr)
}
// ERROR: Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
let argsStr: [CVarArg] = ["Test", "Testing", "The test"]
withVaList(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
The package is available here as well.
As commented in the code above, printing a String via C or a va_list containing Ints works as expected, but when converted to const char *, there's an exception (EXC_BAD_ACCESS (code=EXC_I386_GPFLT)).
So, in short: did I mess up the C side of it or is Swift doing something wrong here? I've tested this in Xcode 11.5 and 12.0b2. If it's a bug, I'll be happy to report it.
This one's a bit tricky: your string is actually being bridged to an Objective-C NSString * rather than a C char *:
(lldb) p str
(const char *) $0 = 0x3cbe9f4c5d32b745 ""
(lldb) p (id)str
(NSTaggedPointerString *) $1 = 0x3cbe9f4c5d32b745 #"Test"
(If you're wondering why it's an NSTaggedPointerString rather than just an NSString, this article is a great read -- in short, the string is short enough to be stored directly in the bytes of the pointer variable rather than in an object on the heap.
Looking at the source code for withVaList, we see that a type's va_list representation is determined by its implementation of the _cVarArgEncoding property of the CVarArg protocol. The standard library has some implementations of this protocol for some basic integer and pointer types, but there's nothing for String here. So who's converting our string to an NSString?
Searching around the Swift repo on GitHub, we find that Foundation is the culprit:
//===----------------------------------------------------------------------===//
// CVarArg for bridged types
//===----------------------------------------------------------------------===//
extension CVarArg where Self: _ObjectiveCBridgeable {
/// Default implementation for bridgeable types.
public var _cVarArgEncoding: [Int] {
let object = self._bridgeToObjectiveC()
_autorelease(object)
return _encodeBitsAsWords(object)
}
}
In plain English: any object which can be bridged to Objective-C is encoded as a vararg by converting to an Objective-C object and encoding a pointer to that object. C varargs are not type-safe, so your test_va_arg_str just assumes it's a char* and passes it to puts, which crashes.
So is this a bug? I don't think so -- I suppose this behavior is probably intentional for compatibility with functions like NSLog that are more commonly used with Objective-C objects than C ones. However, it's certainly a surprising pitfall, and it's probably one of the reasons why Swift doesn't like to let you call C variadic functions.
You'll want to work around this by manually converting your strings to C-strings. This can get a bit ugly if you have an array of strings that you want to convert without making unnecessary copies, but here's a function that should be able to do it.
extension Collection where Element == String {
/// Converts an array of strings to an array of C strings, without copying.
func withCStrings<R>(_ body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
return try withCStrings(head: [], body: body)
}
// Recursively call withCString on each of the strings.
private func withCStrings<R>(head: [UnsafePointer<CChar>],
body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
if let next = self.first {
// Get a C string, add it to the result array, and recurse on the remainder of the collection
return try next.withCString { cString in
var head = head
head.append(cString)
return try dropFirst().withCStrings(head: head, body: body)
}
} else {
// Base case: no more strings; call the body closure with the array we've built
return try body(head)
}
}
}
func withVaListOfCStrings<R>(_ args: [String], body: (CVaListPointer) -> R) -> R {
return args.withCStrings { cStrings in
withVaList(cStrings, body)
}
}
let argsStr: [String] = ["Test", "Testing", "The test"]
withVaListOfCStrings(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
// Output:
// Printing 3 strings...
// Test
// Testing
// The test

Print Unicode in a formatter

I need to Print a Unicode Character whose value should not be hard-coded
This is how to Print unicode in General
print!("\u{2518}");
now the 2518 should not be hard-coded, i need to provide it like that
print!("\u{}", 0x2518);
I've tried print!("\u{{}}", 0x2518); but didn't work
Thanks in advance
You can use std::char::from_u32 for this. Because not all values of a u32 represent valid Unicode Scalar Values, you need to handle an error-case:
fn main() {
let i = 0x2518;
println!(
"{}",
match std::char::from_u32(i) {
Some(c) => c,
None => '�',
}
);
}

How can I use a macro value as a part of a function name in stable Rust? [duplicate]

This question already has answers here:
How to prefix/suffix identifiers within a macro? [duplicate]
(3 answers)
Closed 6 years ago.
I'm trying to write a macro like this:
macro_rules! impl_numeric_cast_methods {
($($ty:ty)*) => {
$(
fn from_$ty(v: $ty) -> Self {
v as Self
}
)*
}
}
The from_$ty bit doesn't work due to macro hygiene. I found that if $ty was an ident then I could (on unstable) possibly use concat_idents! except that that apparently doesn't work either.
There's a blog post about this issue and future plans to fix it, but my question is: how can I do this at all in today's Rust stable (1.15)? Is there a workaround?
As a reasonable workaround, you can add the function names as extra parameters. It's not elegant but it works:
macro_rules! impl_numeric_cast_methods {
($($ty:ty, $from_ty:ident),*) => {
$(
fn $from_ty(v: $ty) -> Self {
v as Self
}
)*
}
}
Then call like:
impl_numeric_cast_methods(i8, from_i8, u8, from_u8);
A second macro could make the invocation shorter, but that would overcomplicate things in my case.

Converting Rust macro types into expressions

I'd like to assume a given type implements some trait (e.g. Default) with a method (e.g. default()). I want to call that method and store its value into a local variable. Here is a general idea of it:
macro_rules! get_default {
( $x:ty = $alias:ident ) => {
let $alias = $x::default();
};
}
fn main() {
// get_default!(i32 = z);
// println!("get_default! {:?} ", z);
println!("i32 default {:?} ", i32::default());
}
Playground link.
When I try that I get an error:
error: expected expression, found `i32`
--> <anon>:3:22
|>
3 |> let $alias = $x::default();
|> ^^
I understand it's because it expects an expression, but I want to limit input to types only. Is there a way to turn $x from ty to expr, or a way to call a method on a type (even if it's potentially missing).
You were almost there. You can hint the expected default type to the compiler and then just use the universal function call syntax:
macro_rules! get_default {
( $x:ty = $alias:ident ) => {
let $alias = <$x as Default>::default();
};
}
fn main() {
get_default!(i32 = z);
println!("get_default! {:?} ", z);
println!("i32 default {:?} ", i32::default());
}
(Playground link)
The key bit is this:
let $alias = <$x as Default>::default();
This casts $x to the Default trait and then invokes the default() method, as you needed.
You can also use a shorthand when you don't need to disambiguate between traits:
let $alias = <$x>::default();
(Playground link)
More General Usage of UFCS
Using UFCS as shown above, you can disambiguate between traits that implement the same methods. This is the 'angle-bracket form' which is useful if the default() method is implemented in two traits.
In this specific scenario, you can also use UFCS more specifically, like so:
let $alias: $x = Default::default();
That alone provides enough information for Rust to infer the correct impl.
(Playground link)

In Haxe, how do you read a variable name inside of a Macro?

I'm trying to use Macros to convert some variable declarations from this:
function test():Void {
var someComp:Component = __SOME_MACRO__();
// Or...
#getCompById var someComp:Component;
// Or even simpler...
getCompById(someComp, Component); //do some fancy macro magic...
// Also, if it's not possible/easy with a variable ...
getCompById("someComp", Component); //with a string of the variable name.
}
... to this:
function test() {
var someComp:Component = cast container.getCompById("someComp");
}
I'm leaning more toward the 3rd option (shorter syntax, same results).
But I have no idea how to write the macro (should it take a String as parameter? An expression?) and how to properly return that as a macro expression.
This is the (broken) code I've got so far:
macro static function getCompById(someVar:Expr, typeVar:Expr) {
return macro {
var someVar:typeVar = cast container.getCompById("someVar");
};
}
Any ideas?
The issue with the code you posted is first that you'd need reification escaping mechanisms for this to work correctly - so the first change would be to use the macro escapes:
return macro var $someVar:$typeVar = cast container.getCompById($v{someVar});
Now there will be some problems with this: It's expecting someVar to be of type String, and typeVar to be of type ComplexType. It's easy to get the string component from an Expr. It's not so easy however to transform an Expr into ComplexType. The easiest way to do that is to use the tink_macros library and use asComplexType
So the (untested) code will look something like:
using tink.MacroAPI;
using haxe.macro.Tools;
macro static function getCompById(someVarExpr:Expr, typeVarExpr:Expr)
{
var typeVar = typeVarExpr.toString().asComplexType();
switch (someVarExpr.getIdent())
{
case Success(someVar):
return macro var $someVar:$typeVar = cast container.getCompById($v{someVar});
case Failure(error): throw error;
}
}