Support defining C-compatible variadic functions in Rust

Support defining C-compatible variadic functions in Rust, via new intrinsics.
Rust currently supports declaring external variadic functions and calling them
from unsafe code, but does not support writing such functions directly in Rust.
Adding such support will allow Rust to replace a larger variety of C libraries,
avoid requiring C stubs and error-prone reimplementation of platform-specific
code, improve incremental translation of C codebases to Rust, and allow
implementation of variadic callbacks.
This RFC does not propose an interface intended for native Rust code to pass
variable numbers of arguments to a native Rust function, nor an interface that
provides any kind of type safety. This proposal exists primarily to allow Rust
to provide interfaces callable from C code.
Rendered

A bit of background: this was inspired by a co-worker who wanted to define a debugging library to intercept certain C calls, for use with $LD_PRELOAD. He wanted to try writing that library in Rust. However, some of the calls he wanted to intercept included variadic functions; that was the only thing stopping him from writing that code in Rust, and forcing him to write it in C instead.

/// Obtain the variable arguments of the current function. Produces a

/// compile-time error if called from a non-variadic function. The compiler
/// will supply the appropriate lifetime when called, and prevent that
/// lifetime from outliving the variadic function.

Having the compiler enforce special lifetime rules for one function sounds really dubious.  Either don't enforce lifetimes or make it work with the normal rules - either with a API that takes impl for<'a>  FnOnce(VaList<'a>), or with the …args option.  (There's no rule that the extra argument has to be a VaList itself, as opposed to something that can be turned into one.)

@comex I didn't intend it to be a "special lifetime rule", so much as the compiler simply defining and passing the appropriate lifetime.
I don't really think an API based around calling a closure would work very smoothly, but I'd be open to switching to the ...args option. And having that be an object that can produce a VaList (borrowed from that object), rather than the VaList itself, seems plausible. I might experiment with that and see how it turns out. Suggestions for the name of such a type?

I'd also appreciate feedback from appropriate compiler folks, regarding what solution might make the most sense from a compiler-internals point of view, in terms of preventing the type from outliving the variadic function associated with it.

Either don't enforce lifetimes or make it work with the normal rules

People have talked about introducing a special 'fn lifetime which represents the lifetime of the current function. This could be a good usecase for that.
ie.
impl<'a> VaList<'a> {
    pub unsafe fn start() -> VaList<'fn>
}

`

The only safe way that comes to mind is requiring the function take a VaList<'a> lang item type and not use the same lifetime passed to it (anonymous or not, elision would still see it) anywhere else in the signature, and we synthesize the necessary intrinsic calls to create the VaList.

The RFC says that only libc would be allowed to provide impls of VaArg. Does this mean that it is an unstable intrinsic or language feature? Or does it mean that libc becomes explicitly magical among creates?

The RFC says that only libc would be allowed to provide impls of VaArg. Does this mean that it is an unstable intrinsic or language feature? Or does it mean that libc becomes explicitly magical among creates?

Since all the relevant types in libc are type aliases to built-in types, no magic is needed to limit something to libc. The impls just need to be limited to core.

@mark-i-m Fixed now, since libc's types are just type aliases.

@eddyb OK, based on your comment, I've tried reworking the RFC so that it accepts a VaList<'a> as an argument, with the syntax args: ... (not mentioning the type or its lifetime, so you can't reuse it elsewhere in the signature); the compiler can then pass an appropriate lifetime that prevents the VaList from outliving the variadic function. Does that look reasonable to you?

@joshtriplett Not bad, I don't have any more suggestions at this time, as I believe that solves the problem of the short-lived data escaping the function.

This is getting long, so I write it as the main comment here.
You mentioned

A function declared with extern "C" may accept a VaList parameter, corresponding to a va_list parameter in the corresponding C function. For instance, the libc crate could define the va_list variants of printf as follows:
unsafe extern "C" { pub fn vprintf(format: *const c_char, ap: VaList) -> c_int; }

This will conflict with impl Drop for VaList which associated va_end to it. Consider
unsafe extern fn forward_to_printf(fmt: *const c_char, ap: ...) -> c_int {
    vprintf(fmt, ap)
}

Here ap is moved into vprintf, which means vprintf should be responsible for dropping ap. However, in C, it is the caller's responsibility to call va_end:
int forward_to_printf(const char* fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}

That means vprintf cannot take VaList as-is. Perhaps it could provide a method:
impl VaList {
    unsafe fn as_va_list(&mut self) -> va_list;
}

so the caller still retains the ownership of VaList:
unsafe extern fn forward_to_printf(fmt: *const c_char, ap: ...) -> c_int {
    vprintf(fmt, ap.as_va_list())
}

Uniquely-borrowing the VaList instead of moving it will allow you to translate weird things like this into Rust:
void just_print_one(va_list ap) {
    printf("%d\n", va_arg(ap, int));
}
void print_nums(size_t n, ...) {
    va_list ap;
    va_start(ap, n);
    for (size_t i = 0; i < n; ++ i) {
        just_print_one(ap);
    }
    va_end(ap);
}
int main() {
    print_nums(4, 1, 2, 3, 4);
}

Actually, would it be even better if args: ... means the type of args is &mut VaList instead of VaList? And va_list is an alias of &mut VaList.

On Sun, Sep 03, 2017 at 05:11:16PM +0000, kennytm wrote:

@joshtriplett Just for consistency, the args: has no meaning here 😄. This is really outside of the scope of this RFC, feel free to ignore it.

I have no objection to it, at all; I just don't want to mix it in with
this RFC unless there's a good reason to do so.  The argument names in
an extern "C" fn serve primarily as documentation for the external
function's argument names, and ... doesn't have an argument name in C,
so I don't think the consistency buys us anything.

@kennytm, your example is, at least, not portable. Quoth the C99 standard (emphasis mine):

The type declared is

va_list

which is a complete object type suitable for holding information needed by the macros va_start, va_arg, va_end, and va_copy. If access to the varying arguments is desired, the called function shall declare an object (generally referred to as ap in this subclause) having type va_list. The object ap may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap.

On AArch64, the Tiny C Compiler defines va_list as follows:
typedef struct {
    void *__stack;
    void *__gr_top;
    void *__vr_top;
    int   __gr_offs;
    int   __vr_offs;
} va_list;

which means this example won't work (probably, since I don't have an AArch64 machine to test). This also demonstrates that va_list cannot be defined as an alias for &mut VaList on the Rust side if perfect ABI compatibility is desired. Well, unless the compiler implements some really exotic semantics for this reference type...
On x86-64 for targets other than Win64, TCC defines va_list as a one-element array containing a similar structure, which makes the example work; on all other architectures, va_list is char * and it doesn't work.
Interestingly though, va_end seems to be a no-op on all architectures supported by TCC.

@fstirlitz have you seen my update?

Anyway, yes, the fact that va_list may be non-pointer-sized means that it cannot be a pointer or reference, meaning a (&mut) VaList cannot be simply coerced to a va_list without a new coercion rule. Alternatively we just remove impl Drop for VaList and let the compiler unconditionally insert va_end at the exit block of variadic functions, similar to va_start.

Interestingly though, va_end seems to be a no-op on all architectures supported by TCC.

I believe it is no-op on x86_64 and all ARMs. Still, if we are using LLVM intrinsics, the va_end is still needed:

Calls to llvm.va_start and llvm.va_copy must be matched exactly with calls to llvm.va_end.

According to ldc-developers/ldc#1744, not calling va_end will confuse the optimizer.

@kennytm The intent was that the type behaves as though it implements Drop, which should also cause the compiler to treat it as a type that needs appropriate destruction.  I agree that that doesn't quite match the move semantics of passing a VaList, though. I don't think it makes sense to pass a &mut VaList, though, because that seems more like va_list * than va_list.  And I'd rather not have VaList and va_list be separate types; I really prefer the idea of declaring an extern "C" fn as taking a VaList somehow.
So, based on that: @eddyb, could you weigh in on this aspect? Does it makes sense to treat this type as implementing Drop? Or, how should we handle passing a VaList to an extern "C" fn that expects a va_list?

Move semantics when passing VaLists wouldn't fit here anyway, because passing a va_list to a C function need not invalidate the va_list. You may want to pass a va_list to a C function which you know to make its own va_copy of it, and then keep using the original va_list. The passage from the standard I cited above seems carefully worded to allow this kind of usage.

One possibility:

Variadic functions automatically get a call to va_start at the entry point and va_end at all exits (rather than using Drop, so that the semantics work properly).
But cloning a VaList does not use the va_copy intrinsic, because of the various ways that would be inflexible (e.g. you could never return a cloned VaList because you're supposed to use va_end in the function that calls va_start).
Instead, rustc manually duplicates VaList objects based on platform-specific knowledge of their format.  On all current architectures, that's just a memcpy.  (But to maximize flexibility for future architecture ports, VaList does not implement Copy.)
Also, Rust guarantees that is safe to move VaList like any other type, including between functions, whereas the C standard seemingly only allows passing it to a function as a plain argument.

That last point is potentially sticky, because some ABI could hypothetically define a va_list struct that contains internal pointers, and have the C compiler automagically fix them up when a va_list is passed as an argument.  I don't know why one would ever do that, but… I don't know why one would ever design va_list the way the AArch64 procedure call standard does, either, yet there it is.  (The long struct mentioned by @fstirlitz isn't TCC-specific; here's a link to said standard.)

@fstirlitz Do you know of any real functions that take a va_list but are guaranteed to copy it before use?  If they're not common in practice, it's not the end of the world to require the caller to do a redundant copy, especially since the backend will usually be able to optimize it away (on architectures where it's a memcpy, i.e. presently all of them).

I think this might be a solution:
The intrinsics have the following interface:
pub struct VaList<'a>; // Opaque
pub struct VaListHandle<'a>;

impl<'a> VaList<'a> {
    pub fn get_args(&self) -> VaListHandle<'a>;
}

impl<'a> Drop for VaList<'a>; // calls va_end

impl<'a> VaListHandle<'a> {
    pub unsafe fn arg<T: VaArg>(&mut self) -> T; // va_arg
    pub unsafe fn copy(&'a self) -> VaListHandle<'a>; // va_copy
}

va_start is called implicitly by the compiler when args is passed in, just like the current version of the RFC.
Since all of the VaListHandles are tied to the lifetime of the VaList, they cannot outlive the function. However, dropping a VaListHandle does not va_end, so you can keep doing whatever until VaList is dropped, too.
Also, since VaList is not Copy or Clone, the only way you can get it is from the compiler via args, so there is exactly one such struct that will get dropped, and exactly one such struct to which all other lifetimes are bound.

impl<'a> VaListHandle<'a> {
    // ...
    pub unsafe fn copy(&'a self) -> VaListHandle<'a>; // va_copy
}

[...] However, dropping a VaListHandle does not va_end, so you can keep doing whatever until VaList is dropped, too.

That looks wrong. va_lists created by va_copy have to be va_ended.

@comex: I don't know of any such thing in the wild, and admittedly such behaviour would be quite inefficient on targets where va_list is defined like on AArch64 (i.e. a fat struct, for which nevertheless passing a value in an argument list is equivalent to a va_copy already). Still, it seems like valid use to me.
And I don't believe the optimiser would be able to eliminate a redundant copy in the caller, given that it would have to take into account information from across the FFI boundary.

@comex:

Also, Rust guarantees that is safe to move VaList like any other type, including between functions, whereas the C standard seemingly only allows passing it to a function as a plain argument.

Here's TCC's <stdarg.h> again:
#ifdef __x86_64__
#ifndef _WIN64

//This should be in sync with the declaration on our lib/libtcc1.c
/* GCC compatible definition of va_list. */
typedef struct {
    unsigned int gp_offset;
    unsigned int fp_offset;
    union {
        unsigned int overflow_offset;
        char *overflow_arg_area;
    };
    char *reg_save_area;
} __va_list_struct;

typedef __va_list_struct va_list[1];
// ...
#endif
// ...
#endif
// ...

When you declare a va_list variable in your C function, you effectively declare a __va_list_struct, but when you pass such a va_list to another function, you're passing a __va_list_struct * (because arrays decay to pointers in C; the same trick is often used in the definition of jmp_buf). To which one should VaList correspond on Rust side? What does it mean to 'move' such a VaList when calling an extern "C" function?

On Tue, Sep 05, 2017 at 10:16:38PM +0000, Konrad Borowski wrote:

xfix commented on this pull request.

+```rust
+pub unsafe extern "C" fn func(arg: T, arg2: T2, mut args: ...) {

// implementation
+}
+```

+The use of ... as the type of args at the end of the argument list declares
+the function as variadic. This must appear as the last argument of the
+function.  The function must use extern "C", and must use unsafe. To expose
+such a function as a symbol for C code to call directly, the function may want
+to use #[no_mangle] as well; however, Rust code may also pass the function to
+C code expecting a function pointer to a variadic function.
+
+The args named in the function declaration has the type
+core::intrinsics::VaList<'a>, where the compiler supplies a lifetime 'a
I don't VaList type should be in core::intrinsics, as this module is reserved for rustc internals and is not designed be ever stabilized.

@xfix Some parts of intrinsics are stabilized; in particular, copy, copy_nonoverlapping, drop_in_place, transmute, and write_bytes. The following compiles on stable Rust:
fn main() {
    let mut x: u32 = 0;
    unsafe {
        std::intrinsics::write_bytes(&mut x, 0x42, 4);
    }
    println!("{:#x}", x);
}

As does the following:
extern crate core;

fn main() {
    let mut x: u32 = 0;
    unsafe {
        core::intrinsics::write_bytes(&mut x, 0x42, 4);
    }
    println!("{:#x}", x);
}

So I don't think putting this in intrinsics will serve as a barrier to stabilization.

OK, I just made two significant changes in response to feedback.
First, I got rid of the VaArg trait, and made it non-specific how the compiler may enforce that you can only call VaList::arg on FFI-safe types (including #[repr(C)] structs and unions, and non-data-carrying enums with repr-specified discriminants). @ubsan, @cramertj, does this address your concerns in that area?
Second, I stopped mentioning an impl of Drop directly, and instead just talked about the necessary drop semantics. In practice, passing VaList to an extern "C" function has almost the right semantics, effectively handing over ownership, since you cannot use it in the caller after you pass it. However, as @kennytm pointed out, that would imply that the callee calls Drop, rather than the caller. So, I left the exact implementation unspecified, and instead described how the compiler needs to handle drop semantics at the FFI interface.

@joshtriplett I'll just say again that references are FFI-safe, so I don't agree with leaving them out. I'm fine with "all types which aren't currently warned against by the extern "C" lint".

In the interests of not duplicating the checks on extern "C" FFI-safe types (and missing some types in the process), I've changed the explicit list in the RFC to a statement that VaList::arg should accept any type usable in an extern "C" function signature.
@ubsan, this will include references; @xfix, this includes function pointers; in both cases, it'll also include Option of those.

@fstirlitz I haven't seen the syntax extern pub type before. But sure, I can attempt to express the visible interface more clearly.

I don't know that extern type is the right abstraction. extern types, at least as proposed in the latest RFC, are of unknown size. Here, sized types are required for the v***-style functions and impl Clone.

@jethrogb I'm trying to describe the interface as presented to users of it, rather than the implementation. Would it be better if I wrote it in rustdoc style, of /* fields omitted */?

This is another RFC that is carefully tailored to bring Rust closer to full expressiveness of the C ABI, without polluting idiomatic Rust code in the least. It's well-motivated and seems soundly designed as well (at least per a preliminary review with the lang team). Moreover, I believe that all major issues raised by stakeholders on this thread have been addressed (but speak up if that's wrong!)
Thus, I'm putting this up for full lang team review:
@rfcbot fcp merge

I just remembered that #[non_exhaustive] was merged not long ago (#2008); could have used that instead. But it's fine.
More va_list trivia: I discovered that even though GCC and Clang define va_list as a typedef of an ostensibly opaque type __builtin_va_list, that type otherwise behaves identically to TCC's 'traditional' definition as a struct or an array type: it allows assignment (if it's not an array), dereferencing (if it's an array or pointer type), field accesses (if a struct or a pointer to one). This isn't portable in the slightest, but I assume it was intended: it might reduce friction when migrating from another C compiler for a given target. (Although this would also justify supporting &va_arg(ap, ...), which neither GCC or Clang do.)
But anyway, this reason doesn't really apply to Rust, and apparently this RFC's intent is to prefer portability over expressivity, which means there's no reason to expose the inner structure of a VaList.

This isn't really related to this RFC, but to respond to what @fstirlitz said, va_list is often implemented as a single element array.
Due to weird array semantics in C, it prevents straightforward copying (with syntax like va_list ap2 = ap as arrays have to be initialized with braces), allows providing it to functions (arrays on slightest provocation in C become pointers) , allow functions to accept va_list arguments (for some reason in C, an array argument type in a function is quietly considered to be a pointer type, for instance int main(int argc, char **argv) is identical to int main(int argc, char *argv[])).
This is not really to preserve the compatibility with other C compilers on the same target (although it probably will work for that), but rather to avoid simple mistakes without having to implement a completely new type with really unusual semantics. The weird things you can do due to that, like the following example actually working.
void whatever(va_list ap1, va_list ap2) {
    ap1 = ap2;
}

Are just side-effects of an implementation, and aren't actually intended to work.

@xfix: I think that particular example may be actually valid, standard C. va_lists are intended to be possible to pass in an argument list, and passing arguments is defined with simple assignment semantics. It follows that simple assignment to a variable declared as va_list on the argument list should be allowed, and accessing ap1 after this assignment should be equivalent to accessing ap2 before it; but I don't see anythihng else being guaranteed, which makes the example rather silly, even if 'standards-compliant'.
But what I was commenting on is that the entire inner structure of a va_list is completely transparent to user code. You can actually access ap.__stack on AArch64, or ap->gp_offset on x86-64, or do pointer arithmetic on ap on other targets (where va_list is traditionally char *), and GCC will compile it without complaining; even though it could e.g. use void * instead of char *, obfuscate struct member names, or even not give them names at all, given that the definition already comes 'from outside the language', via __builtin_va_list. GCC internals are perfectly capable of doing such tricks and the developers could have used them easily; that they didn't seems to suggest that they do wish to support architecture-specific code that relies on these details.
But this is way off-topic now.

I don't see @comex's question (whether to implement the ABI via LLVM intrinsics or manually) addressed anywhere. And this is a quite important issue: if VaList<'a> is to be implemented purely via intrinsics, then it's impossible to have it implement the Clone trait as proposed, for example.
Why? Here's a puzzle: what does this code do?
fn kopimi<'a>(args: VaList<'a>) -> VaList<'a> {
    args.clone()
}

extern "C" fn bar(args: VaList) -> c_int {
    let mut args2 = kopimi(args);
    unsafe { args2.arg::<c_int>() }
}

If args.clone() is equivalent to a va_copy(..., args), it follows that to fulfil the requirements of the C standard, va_end should be invoked at the end of kopimi with the cloned value, which means it cannot be usable after kopimi returns. And yet the above code will pass the borrow checker with flying colours, given the proposed definition of VaList, and the definition of Clone (which requires the clone's type to be identical to the source value's type, including lifetime parameters).
If by some miracle you manage to overcome that and implement Clone anyway, you better ask yourself: what does this code do?
extern "C" fn foo(mut args: VaList) {
    let mut args2 = args.clone();
    mem::swap(&mut args, &mut args2);
}

If VaList values on the argument lists of extern "C" functions are supposed to correspond to va_list parameters in C functions, which are to be 'leaked', while VaLists stored anywhere else are 'owned' va_lists and should be finalised (by va_end or otherwise), it follows that this will leak the va_list value that was the result of cloning, and finalise the one that was passed from outside: exactly the opposite of what it should do. When foo's caller attempts to invoke va_end on its own va_list, this might even become a double-free bug (because one possible way to implement va_start / va_end is by allocating memory on the heap). And this is all purely safe code.
Or you may ponder this example:
unsafe fn juggle0(mut args: VaList) -> VaList {
    let args2 = args.clone();

    /* play with args */

    args2
}

unsafe fn juggle1(mut args: VaList) -> VaList {
    /* play with args */

    args
}

extern "C" unsafe fn juggle(args: VaList) {
    let mut args0 = juggle0(args.clone());
    let mut args1 = juggle1(args);

    /* play with args0/args1... */

    /* now what? */
}

Inside juggle, args1 should be 'leaked' (because it is the args that was received from C), but args0 should not. But if all a Rust VaList contains is a C va_list value, there is no way the compiler can deduce this without knowing the implementation of juggle0 and juggle1, which may be in a foreign crate far, far away.
Now, I can imagine some solutions to the above problems, but each has its own costs and may noticeably impact how the Rust-side API will look like, so I think they better be solved upfront, instead of committing to a particular API and only later discovering it is impossible to implement safely, or at all.

@fstirlitz You're right.
The more I look at it, the more I think it's a mistake to attempt to provide pseudo-Drop semantics for VaList when the actual requirements on C's va_list don't match the ownership rules of Rust.
Capturing some of the C constraints:

A va_list must not outlive the function that called va_start or va_copy to create it; that function must call va_end.
When passing a va_list to a C function, if the function calls va_arg, the caller can no longer use the va_list.
When passing a va_list to a C function, the caller makes the call to va_end, not the callee. (For instance, vprintf does not call va_end, its caller does.)

The first constraint motivates attempting to provide lifetime semantics in the first place. The second constraint looks similar to transferring ownership in Rust, but that doesn't match the third constraint.
So, at this point I can see two options:

We could provide the raw intrinsics for va_start, va_copy, va_arg, and va_end, and rely on libraries to provide higher-level semantics. Some of the work around 'fn lifetime ascription and immovable types might help here.
We could provide a higher-level VaList, and support normal move and ownership semantics in Rust, which then means we need some special support for interfacing with C FFI functions that pass a va_list instead of variadic arguments. For instance, VaList could use standard Drop semantics (which should theoretically work fine within pure Rust code), and then you'd have to call a method to obtain from a VaList a thing you can pass to a C function expecting a va_list.

Thoughts?

Based on a detailed conversation with @withoutboats on #rust-lang, we think the following plan makes sense:

args: ... will still make args be VaList<'a> for some compiler-provided 'a (equivalent to 'fn).

The compiler guarantees a call to va_end on that VaList at the end of the function with a ... in the signature (and a matching call to va_start at the start).

VaList will not implement Drop *or Clone`
Treat extern "C" fn signatures containing VaList as being equivalent to a C va_list vprintf-style function. Unlike ..., the compiler will never call va_end on that VaList.
To support va_copy, we'll provide a VaList::copy that calls a closure with a VaList<'b> (with 'b != 'a so the lifetime doesn't match that of the self pa), and copy makes the same "va_end on any exit" guarantee.

Do you need a closure? Can you do some trickery like this?
impl<'a> VaArgs<'a> {
    fn copy<'b>(&'b self) -> impl Deref<Target=VaArgs<'b>> + 'a { /* ... */ }
}

@jethrogb va_end must be called after va_copy, and the only way to enforce this is by using a closure.
Destructors don't work because forgetting values is safe.

@plietar I don't mem::forget being safe is any issue here, considering ... is only allowed in unsafe functions.

One of the solutions I had in mind was this:
/* this is inside core::intrinsics; obvious definitions omitted */
#[non_exhaustive]
pub struct RawVaList {
	/*
	 * ABI-dependent. Probably #[repr(C)] or #[repr(transparent)].
	 * Fields may or may not be visible, but either way, the type
	 * should have no safe public constructors.
	 */
}

extern "rust-intrinsic" fn va_end(&mut RawVaList);

impl Drop for RawVaList {
	fn drop(&mut self) {
		va_end(self);
	}
}

#[lang = "va_list"]
pub struct VaList<'a>(&'a mut RawVaList);

impl<'a> VaList<'a> {
	#[lang = "va_copy"]
	pub fn clone<'b, 'c>(&'b self) -> VaList<'c>;
	pub unsafe fn next<T>(&mut self) -> T;
	pub unsafe fn as_ptr(&mut self) -> *mut RawVaList;
	pub unsafe fn from_ptr(raw: *mut RawVaList) -> Self;
}

Some terminology: I'm going to call the contents of a va_list variable in C a variadic context. Above, it is represented by the RawVaList type.
Now, how this works:

Inside a variadic extern "C" function, the Rust compiler invokes va_start, creating a variadic context. This variadic context behaves like a mutable binding declared at function scope, and is dropped (calling va_end) when the function exits, but is not actually bound to any identifier. The identifier declared with the pseudo-type ... is bound to a VaList value wrapping an exclusive reference to this variadic context.
Calling the clone inherent method of VaList similarly creates an invisible variadic context in the caller via va_copy, and wraps a VaList value around an exclusive reference to it; again, this variadic context has ordinary drop semantics, as if the caller of clone was variadic itself. The compiler enforces that the lifetime parameter 'c in the clone method always refers to the lifetime of the caller of clone, and cannot be overridden by user code. (I didn't write this as 'fn, because I find it strange that 'fn in a function signature should refer to the caller's lifetime, but in a function body it refers to the callee's.)
Inside an extern "C" function declared as receiving a VaList argument, the Rust compiler arranges things so that the VaList value wraps a reference to the variadic context received on the argument list (either as a copy, or as a pointer, depending on the ABI). This variadic context is 'leaked', i.e. va_end is not invoked on it.
Passing a VaList value to an extern "C" function is realised as passing a copy of the corresponding variadic context or a pointer to one, depending on what the ABI prescribes. There is, however, no transfer of ownership of the variadic context to which the VaList value refers; it is still dropped as if owned by the caller.
Optionally, passing a &VaList to an extern "C" function could be realised the same way in the ABI. This will enable calling C functions which receive a va_list, but are guaranteed to va_copy it (and therefore not invalidate their argument).
Everywhere else, the VaList type has ordinary Rust semantics.

How this resolves my three examples: they simply fail to compile, because cloning no longer produces a value with the same type (as the lifetime parameter will differ). Calling mem::swap, when valid, is harmless: it simply swaps the references to wrapped variadic contexts, which are still dropped all the same. Leaking a VaList similarly merely leaks the reference. The lack of an impl Clone for VaList may be seen as regrettable, but this type isn't really meant to be passed around in data structures much, so it's not necessarily a huge loss.
It's basically equivalent to closure-based solutions, except the syntax is neater.
One downside of the above scheme is that it makes it awkward to deal with functions which accept a va_list * argument, which has to be written as *mut RawVaList (instead of the obvious *mut VaList). Now, admittedly this is a construct that C code tends to avoid, because it doesn't play well with va_list being an array type; and even though the standard seems to allow it, it only does so in a non-normative (I am told) footnote. But if you're stuck with an interface which defines things like that, you better know how to express it.
The penultimate point also has the consequence that, while this
fn same<T: ?Sized>(a: &T, b: &T) -> bool {
	a as *const _ == b as *const _
}

makes same(&x, &x) return true, this
extern "C" fn same(a: &VaList, b: &VaList) -> c_int {
	if a as *const _ == b as *const _ { 1 } else { 0 }
}

will make same(&args, &args) return zero. I'm not sure how serious this is.

@xfix the goal here is to remove as many footguns as possible.
Additionally va_end must be called from the same function as va_copy. Running it from a destructor does not guarantee this because the value may be passed to another function and destroyed there. This is actually a much bigger footgun than the one I already mentioned. (Also drop counts as a different function, although that can be avoid by inline(always) (but not if the destrictor is called through dynamic dispatch))
Finally, va_end in destructors interacts badly with C functions like vprintf. For these you are supposed to pass the VaList, never call va_arg on it again but still call va_end at the end, even though "ownership" has been transferred to the C function.
Using closures prevents this, since we can guarantee va_copy and va_end are ran from the same function.
@fstirlitz It's not clear to me when in your proposal is va_end called for the copied VaList.
Does the destructor of  VaList call the RawVaList destructor ? Then you run in the same problem described above.

In comparison, the solution proposed by @joshtriplett looks like this :
extern "rust-intrinsic" {
    // These are all permanently unstable and unsafe
    fn va_start<'a>() -> VaList<'a>;
    fn va_next<'a, T: VaArg>(args: &VaList<'a>) -> T;
    fn va_copy<'a, 'b>(args: &VaList<'a>) -> VaList<'b>;
    fn va_end<'a>(args: VaList<'a>);
}

#[repr(C)] // or transparent ?
struct VaList { /* implementation detail */ }

impl VaList {
    // Must be called from a variadic function.
    // The "args: ...VaList" syntax is essentially sugar for this,
    // where the function body is passed as the closure.
    unsafe fn start<F, R>(f: F) -> R
        where F: for<'a> FnOnce(VaList<'a>) -> R
    {
        let args = va_start();
        let result = f(args);
        va_end(args);
        result
    }

    fn copy<'a, F, R>(self: &mut VaList<'a>, f: F) -> R
        where F: for<'b> FnOnce(VaList<'b>) -> R
    {
        let args = va_copy(self);
        let result = f(args);
        va_end(args);
        result
    }

    unsafe fn arg<'a, T: VaArg>(self: &mut VaList<'a>) -> T {
        va_arg(self)
    }
}

This doesn't deal with unwinding, but it could.
As far as I can tell, this has no footgun or tricky undefined behaviour.
The only two unchecked invariants are :

VaList::start must be called in a variadic function
VaList::arg must not be called more times than there are arguments, or with an incorrect type parameter.

The first one can be prevented by the args: ... syntax in the function parameters. The second is a core shortcoming of the C stdarg API, and can't be worked around.

I am saying that
fn foo(ap: VaList) {
	// ...

	let ap2 = ap.clone();

	// ...
}

effectively becomes
fn foo(ap: VaList) {
	let mut _ap2: RawVaList; // invisible to user code

	// ...

	_ap2 = va_copy(ap.0);
	let ap2 = VaList(&mut _ap2);

	// ...
}

and
extern "C" fn foo(mut args: ...) {
	// ...
}

becomes
extern "C" fn foo(...) {
	let mut _args: RawVaList = va_start(); // invisible to user code
	let mut args = VaList(&mut _args);

	// ...
}

RawVaLists are dropped normally; they are owned by the function, but aren't accessible directly (they don't actually have names), so they cannot be moved outside the function. This 'action at a distance' will of course require special support from the compiler. The compiler also ensures that giving VaLists to extern "C" functions doesn't actually pass a pointer, but a copy the underlying value, unless the ABI specifically requires passing by pointer.

@fstirlitz That makes more sense thanks.
I think your solution works, you are essentially using the invisible RawVaList to execute code at the end of the block, as a replacement for the closure.
The issue with this is it makes this API very special from the compiler's perspective. It doesn't really fit well wit the language.
The closure based solution OTOH barely needs any compiler support. It only needs 4 new intrinsics which map directly to LLVM intrinsics, and a way to mark a function as variadic. It doesn't even need special syntax for that, just an attribute could work by using VaList::start. The special x: ... argument syntax is just sugar.

Compiler developer's perspective: just don't have Drop and have the compiler always know when the original variadic call was received and emit va_end in the same function, potentially also doing the same for va_copy, or just having unsafe va_copy that requires manual pairing with va_end.
Just don't abuse Drop for this.

As @joshtriplett described earlier, I believe we can have an API where we guarantee that a va_start or va_copy called in Rust is paired with a va_end in the same function call. Otherwise of course we provide no correctness guarantees (in particular, whether or not a call to arg is UB).
In general, the way to do this is to use a closure, like the scoped threadpool trick. The equivalent of va_copy in Rust would look like this:
// Note, the lifetime on VaList is invariant
impl<'a> VaList<'a> {
     pub fn copy<'copy, F, T>(&self, f: F) -> T
         where F: FnOnce(VaList<'copy>) -> T + 'copy, T: 'copy
}

We could do the same thing for the VaList received from the ... args: you could be required to call a .start() method on it. However, this feels unnecessary to me because we are already generating code as a part of the ... arg contract anyway.
This seems like an excellent, minimal way to integrate this feature into Rust. All we are introducing are:

A lang item and some intrinsics
Some glue code generation in ... fns
A moderately safer wrapper around those intrinsics

The footgun reduction in these latest proposals is seriously impressive. Any more improvements and this won't even feel like C anymore (in a good way!).
I do have an actual question though: Is it possible to call a "...-taking" or VaList-taking Rust function directly from Rust? I'm not sure if this is desirable, since it could lead to abusing VaList for pure Rust variadics, but if it's impossible then we might also end up with VaList-using codebases having to keep around a C shim even after the C code calling that VaList function also got rewritten in Rust. Either way, it wasn't obvious to me from the RFC whether this is or should be possible and/or defined behavior.

Is it possible to call a "...-taking" or VaList-taking Rust function directly from Rust?

I think it should be allowed, but highly discouraged. Rust can already call extern variadic functions, so there's no reason to restrict it when it comes to functions defined in Rust.

I'd like to point out a section that I think was missed (under va_start):

The parameter parmN is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the , ...). If the parameter parmN is declared with the register storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined.

(note):

the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.

this means, basically, that the argument right before the ... may not have type, for example, char

I'm very much against C's variadic functions and I do not want support for it in Rust nor require support for it for future Rust backends.

@ubsan llvm's intrinsic for va_start does not take the last argument. It infers it directly from the signature.
I don't know what it means wrt to that section though. Does the undefined behaviour never occur, or is it still UB if the last argument is char.
https://llvm.org/docs/LangRef.html#llvm-va-start-intrinsic

@plietar I assume this is not an issue with LLVM. Not all C UB has to be LLVM UB.

Also, would it not be possible to just make VaList !Move?

Thanks to some excellent work by @withoutboats, the current version of the RFC should address all of the potential issues with lifetime. VaList no longer implements Clone or uses any of the Drop machinery; instead, the compiler inserts calls to va_start and va_end at the start and end of variadic functions, and VaList::copy calls va_copy, calls the closure passed to it, and then ensures a matching va_end.

@ubsan: I'm not sure why the standard excuses not supporting these cases (well, the register one I can understand at least), but many implementations will in fact allow it.
I mean, offsetof(struct foo { struct bar { int z; int y; } x; }, x.y) is also technically undefined behaviour, and yet every compiler does what you want.
VaList cannot be immovable (even only after borrowing), because you may need to pass it to an extern "C" function, which (logically) gives up ownership. This can be special-cased, but...

@Zoxc
Keep in mind that this is FFI feature, rather than general purpose Rust feature. Most programs won't be using it (especially because it requires unsafe). However, when it's needed, it's needed. For instance, this feature is needed to fully port C APIs in event somebody would want to rewrite them in Rust - example of APIs using variadic arguments are: standard C library, SQLite, seccomp, SASL plugins (to extent of requiring variadic arguments support for writing new plugins as they take variadic callbacks), gstreamer, DBus, ncurses, Lua, Python, curl, Xorg, SDL, WxWidgets, pam_syslog, GLib, GMP, Windows APIs (Wine).
And I wouldn't be surprised if there was more, I just quickly checked /usr/include on my computer. All of those APIs outright require this feature to be fully ported to Rust while letting old C code still call those. It's possible to have C stub specifically for those ... functions, but wouldn't it be easier to allow those to be implemented in Rust.

Keep in mind that this is FFI feature, rather than general purpose Rust feature

So, I'm somewhat struggling with this idea when trying to form an opinion about this RFC (and #2102). I don't believe that we can really make that distinction. The feature will exist and there is no reason for people to use it for whatever they like. I get that we can make this less ergonomic by making it unsafe, but that just means that programmers have a trade-off between using a varargs function which is ergonomic in the variable number of arguments but not in the unsafe-ness vs a non-varargs function which is ergonomic by being safe, but less ergonomic by requiring a fixed number of arguments. Furthermore, I am concerned that once this exists in the language, there will be pressure to make it more ergonomic, either by further (small and hard to object to) language changes or by some clever macro or something.
To be clear, I am not outright against this feature, but I think it only makes sense to evaluate it as a Rust feature, not as an 'FFI feature' because the latter simply does not exist.
Thoughts on adding this feature:
pros:

better C FFI (and I 100% buy the argument that it is essential for Rust to have excellent FFI support)
solves a real (if very niche) use case

cons:

seems like a lot of future possible interactions: variadic generics, default/named fields, 'proper' variadic arguments for Rust functions, etc.
for most (but not all) use cases, it is fairly easy to have a C stub function to fix this
adds syntax and semantics for a fairly narrow use case (i.e., poor cost/benefit ratio)

Anyway, I stand by approving merging this RFC, I just wanted to expand on my position. I think this should probably have a relatively long stabilisation period - I'd want to be sure about interactions with possible future features before stabilising, but getting this on nightly sooner rather than later seems like a win to me.

@nrc I do understand your point, and I fully agree that we have to evaluate it in the context of the entire language. I think it's useful to position this as "you only want this for FFI", and the unsafety and limitation to extern "C" functions and C-compatible types will help keep its usage to that case. But that doesn't stop us from needing to discuss its interaction with everything else.

I think this should probably have a relatively long stabilisation period - I'd want to be sure about interactions with possible future features before stabilising, but getting this on nightly sooner rather than later seems like a win to me.

I agree completely. And in nightly we may decide based on experience to adjust the feature, or to stabilize some subset of it.

(Signed off for @cramertj, who is on vacation)

The feature will exist and there is no reason for people to use it for whatever they like.

Sufficiently determined programmer will misuse pretty much any feature of a programming language. That said, this feature provides many safe-guards against misuse for things other than FFI.

Requirement to use unsafe while calling a function.
Not being able to know when argument list ends (this one practically blocks most uses of this like default arguments).
Only accepting types with C representation. This list doesn't include non-Copy types other than &mut T.

(lack of type safety probably won't stop somebody who wants to misuse features, so it's not a point)
Additionally, Rust offers macros and array literals which are safe and further reduce the need for C style variadic arguments outside of FFI.

On September 14, 2017 4:04:21 PM PDT, "Paul Liétar"<EMAIL_ADDRESS>wrote:

plietar commented on this pull request.

+arguments, using an ellipsis (...) at the end of the argument
list. For
+compatibility, unsafe Rust code may export a function compatible with
this
+mechanism.

+Such a declaration looks like this:
+
+```rust
+pub unsafe extern "C" fn func(arg: T, arg2: T2, mut args: ...) {

// implementation
+}
+```

+The use of ... as the type of args at the end of the argument list
declares
+the function as variadic. This must appear as the last argument of the
+function, and the function must have at least one argument before it.
The
+function must use extern "C", and must use unsafe. To expose such
a
This is an interesting point. So far the design assumes a singe
VaList type.
It seems like we may need one per calling convention available on your
platform.

Only if the set of types extractable depends on the ABI.

@joshtriplett

Only if the set of types extractable depends on the ABI.

Not only, because we want to support passing  a VaList around rust abi functions, thus we need to distinguish  the ABI of the VaList. For eg, args in foo and args in bar would have different layouts, so using a single baz like below can't work.
extern "win64" fn foo(n: u64, args: ...) { baz(n, args) }
extern "sysv64" fn bar(n: u64, args: ...) { baz(n, args) }
fn baz(n: u64, args: VaList) { ... }

Instead we would need different types, and possibly a trait to abstract the API. Eg
trait VaList {
  fn arg();
  fn copy();
}

mod win64 {
  struct VaList { }
  impl super::VaList for VaList { }
}

mod sysv64 {
  struct VaList { }
  impl super::VaList for VaList { }
}

fn baz<T: VaList>(n: u64, args: T) { ... }

I was thinking more along the lines of struct VaList<'a, C: CallingConvention>. This puts us in “be generic over calling conventions” territory so I'm going to reference https://github.com/rust-lang/rust/issues/40710

The other option would be to store VaList as a sum type, with a variant for each supported ABI, but that would have runtime overhead.
@jethrogb Trying to do this with generics seems challenging on the implementation side; defining separate types seems much easier.

@xfix it's trivial to write a #[repr(C)] thing that is non-copy. #[repr(C)] struct Foo { x: u8 }. In fact, now that drop flags don't exist (anybody remember those?) you can even have repr(C) types with destructors.

@jethrogb Trying to do this with generics seems challenging on the implementation side; defining separate types seems much easier.

There is not much difference between impl VaListWin64 and impl VaList<Win64>.

@jethrogb I hadn't thought of that. Thanks for the clarification; that seems straightforward enough.

@jethrogb I hadn't thought of that. Thanks for the clarification; that seems straightforward enough.
However, I started looking into this (along with @withoutboats), and it turns out LLVM has extremely limited support for this. It exists in only one case, for support of ms_abi on platforms that default to the sysv ABI. And the underlying intrinsics do not support multiple ABIs in a reasonable way; LLVM just makes assumptions based on the calling convention of the current function.
Based on that, I don't think it's reasonable to complicate the common case (e.g. making VaList a trait and requiring functions using it to declare themselves as generic over it) for the sake of that particular use case. I'm going to add an "unresolved question" to the RFC, and mention some potential solutions for this. But for a first pass, I'd like to support this for extern "C". We can handle the rest during the stabilization period and experiment with potential solutions. If this is primarily a special-case for one ABI, we might want to treat it accordingly.

Why isn't VaList using Iterator for its arguments ?

@bestouff (1) There's no ending condition (next() never returns None) (2) the arguments can have different types (think printf)

@tomwhoiscontrary We'd still need a syntax that distinguishes between passing around a VaList (as in functions like vprintf) and passing variable arguments interpreted as a VaList (as in functions like printf). Given the need for both syntaxes, I feel like mut args: ... is as good a syntax as any, and I'd like to avoid bikeshedding unless there's a major motivation to change it.
Also, we do want the ability to pass around the VaList. Ideally, I'd say that it could use the 'fn lifetime, if that gets adopted. But in the absence of that, I'd like to leave it unspecified and let the compiler fill it in with an equivalent.

I am afraid I arrive many days after the fair but I still concur completely with @tomwhoiscontrary. How can this PR been accepted within a single month whereas it is reserving a dedicated syntactical token for such a specific and rare feature?

reserving a dedicated syntactical token for such a specific and rare feature

Because the dedicated syntactical token has been in Rust since 1.0.

@jethrogb this is not the point. My remark would have been the same if the feature had proposed * or >>. Using token in specific contexts make them unavailable for possible future extensions in the same context (even if they are already used for other non conflicting features). We do not have many combinations of tokens made of sigils (or rather not many of them that are human readable and have strong cuggesrive power like ...) so we should decide with great care when to carve their (possibility multiple) usage in the stone. The scope of the proposed feature does not sounds sufficient large to me to prevent any future use of ... in similar contexts.

Just a quick note -- RFCs work toward some initial consensus on points like syntax or naming, but these are routinely iterated on prior to stabilization. IOW, this shouldn't be taken as a blocker for the RFC or its implementation, but rather a discussion to continue on the tracking issue and resolve prior to stabilization.

@contactomorph But @jethrogb is referring to the fact that this exact syntax is used when providing prototypes of extern C functions which take variadic arguments.

On September 28, 2017 2:53:09 PM PDT, Eddy Cizeron<EMAIL_ADDRESS>wrote:

@jethrogb this is not the point. My remark would have been the same if
the feature had proposed * or >>. Using token in specific contexts
make them unavailable for possible future extensions in the same
context (even if they are already used for other non conflicting
features). We do not have many combinations of tokens made of sigils
(or rather not many of them that are human readable and have strong
cuggesrive power like ...) so we should decide with great care when
to carve their (possibility multiple) usage in the stone. The scope of
the proposed feature does not sounds sufficient large to me to prevent
any future use of ... in similar contexts.

This RFC does not reserve the syntax of mut args: ... for every prototype, only those with unsafe extern "C". We can still define it for native Rust in the future if that makes sense.

We can still define it for native Rust in the future if that makes sense.

I'm not sure that leaving open the option of having three different meanings for ... makes it any better!
I take @aturon's point, though - the RFC as a whole is clearly good, and we can defer all work on the bikeshed until later. Perhaps it makes sense for the first cut not to use ..., and then to add that and see how much better it makes things.

@jethrogb & @withoutboats : Ok I didn't know it was already a valid syntax for a related feature. This certainly diminishes the relevance of my point. However I still find unfortunate that such a specific syntax is reserved just for compatibility with C. Would'nt it have been possible to define a specific type from the beginning in order to handle those cases?

@contactomorph What's a lot more likely is that our variadic system would require a type of some kind at the beginning, because Rust is a type safe language in a way that C is not.

This RFC has been merged! The tracking issue keeps the syntax explicitly opened as a not-completely-resolved question; further discussion on that point should move over to the tracking issue.
Thanks @joshtriplett!

The RFC as accepted proposes putting VaList in core::intrinsics. However, in https://github.com/rust-lang/rust/pull/49878 , @dlrobertson observed that core::intrinsics has a module-level #![unstable] attached to it, requiring the core_intrinsics feature to use. On that basis, he suggested putting it in core::ffi instead. If that seems reasonable, I could update the RFC to change the proposed location of the API.
(I'd like to avoid bikeshedding this if possible. It definitely has to go in core so that it works without std. The exact location in core doesn't matter much. core::ffi seems like the appropriate place to me.)

@joshtriplett that seems reasonable, although I want to make sure - it's still on unstable, right?
core::intrinsics seems like an incredibly weird place for VaList and associated things.

@ubsan It's still going to be unstable until stabilized, yes. The issue was that it'd be non-trivial to ever stabilize bits of core::intrinsics.
Also, I think core::intrinsics still makes sense for the underlying functions like va_start and va_arg, which we likely won't stabilize, unlike the higher-level VaList interface.

@joshtriplett right, that makes sense. We really don't want to stabilize bits of core::intrinsics - we did it once with transmute, and it's... eergh

I've started implementing variadic functions in rust, but some people have suggested changing the syntax to pub unsafe extern "C" fn func(fixed: u32, mut args: ...VaList). The benefit of this being, this will be closer to the syntax used for variadic generics. If we go this route, this will also mean I will not have to add another ast::TyKind and hir::TyKind, which will drastically simplify the code required.

@dlrobertson Writing VaList gets into questions of "but what about lifetimes". We discussed that alternative as part of the RFC and the syntax we settled on didn't have that. Could we please stick with just mut args: ... if possible?

@joshtriplett I have git branches with each implemented, just not generating the va_start/va_end yet. My main concern is the diverging syntaxes for variadic generics and variadic arguments.

Writing VaList gets into questions of "but what about lifetimes".

I'm not sure what is meant by this? The VaList is generated inside the function, so it must not be able to escape. As a result, the type we generate in typeck must be subst with a scoped region for the given function. Then you get a lifetime error when you run something like the following.
fn test(fixed: i32, ap: ...VaList) -> VaList { ap }
// or even
fn test<'a>(fixed: i32, ap: ...VaList<'a>) -> VaList<'a> { ap }

Could you explain more about the complexity that would create?

The complexity is just a side point and mainly has to do with the internals of parsing in the compiler. Either way we converge after typeck.
Using ... syntax:

Parsing

Add a new TyKind to the ast and hir (not TyS)
Parse the new type in parse_ty_common
set variadic for the function if TyKind::VarArgs was found

Using ...VaList:

Parsing

Add variadic to the ast and hir Arg
If we find ... eat it and set variadic for the arg
set variadic for the function if arg.variadic == true

Adding a new TyKind is fairly invasive.

I'm not sure what is meant by this? The VaList is generated inside the function, so it must not be able to escape. As a result, the type we generate in typeck must be subst with a scoped region for the given function. Then you get a lifetime error when you run something like the following.
fn test(fixed: i32, ap: ...VaList) -> VaList { ap }
// or even
fn test<'a>(fixed: i32, ap: ...VaList<'a>) -> VaList<'a> { ap }

I believe the issue is that you're writing a type that has a lifetime, except it's not possible to write the correct lifetime as there is no name for it. By writing mut args: ... you're sidestepping the issue because you're not naming the type.

I believe the issue is that you're writing a type that has a lifetime, except it's not possible to write the correct lifetime.

Good point. That could indeed be confusing. For now I'll continue with just ... then.

On December 10, 2018 9:04:00 PM PST, Dan Robertson<EMAIL_ADDRESS>wrote:

@joshtriplett I have git branches with each implemented, just not
generating the va_start/va_end yet. My main concern is the
diverging syntaxes for variadic generics and variadic arguments.

That's a feature. This is specific to extern C functions, and Rust type-safe variadics of any kind can and should be different.

I also see it as a good thing that C variadics get a syntax which is similar enough to variadic generics to be unsurprising, but still distinct enough that it's hard to get confused about which feature you're looking at. Because they are two very different and fundamentally incompatible features.

@dlrobertson Writing VaList gets into questions of "but what about lifetimes"

This is easily solved by checking that the lifetime parameter of VaList doesn't show up anywhere else in the signature.
It needs to be an "universally quantified" lifetime anyway, just like VaList::copy, so that the body of the function is checked with 0 assumptions, and without the type being explicitly spelled out, we would have to synthesize that ourselves somewhere later in the compiler.

@dlrobertson got a bit into the weeds of the implementation, but this is my perspective on why I think it's better for the user to write out VaList:
With e.g. args: VaList... you're explicit that the variadics you're using are C ones, and what the mechanism you interact with to extract arguments, is (i.e. that you have a VaList value).
I'd rather have args: VaList... (C) vs args: A... (VG) than args: ... vs args: A....
We could even rename VaList to make it clearer it's C variadics (CVaList?).
(Also, a random note: Pat: ...Type or Pat...: Type are suboptimal choices of syntax when you take into account Pat: Type becoming Pat syntax)

That seems like revisiting the same argument that was made and explored during the RFC. Is there a new argument here that wasn't previously explored?

Added a comment on https://github.com/rust-lang/rust/pull/57760, but realized I should probably post here too. We need a library feature-gate for VaList and a language feature-gate for C-variadic definitions. In addition, a language feature gate cannot have the same name as a library feature gate. As a result, I think we're forced to use two feature gates:

c_va_list: library feature gate forVaList
c_varaidic: language feature gate for C-variadic function definitions

@dlrobertson Sounds good to me, go for it. :)

Just FYI @varkor fixed the issue with feature-gates so the c_variadic feature enables both core::ffi::VaList and Rust defined C-compatible variadic functions in https://github.com/rust-lang/rust/pull/57760


Rewrite

Fixes #32
Fixes #34
Fixes #9

Ok, I'm going to merge this. Thanks for help @isiahmeadows and @polytypic !


Fix css classnames in admin panel [NEXT YEAR]

ClassNames used for the admin panel css are confusing and not well-descriptive. For instance, "members-card" is not a good descriptive name for the jobs card in admin panel since it can be confused with other files. Therefore, we need to rename the classNames to hold more specific and descriptive names correlating to their respective files and functions.

Hi @SuelaCark is it still available?
I would like to work on it.

@SuelaCark members-card is a global className for all of the cards, not specifically for the jobs cards. But yeah, I agree we have to come up with more descriptive classNames.


Create build-time-blame.yml

This is a new plugin. I am the sole contributor to the GitHub repository:
https://github.com/jenkinsci/build-time-blame-plugin
The original hosting request is here:
https://issues.jenkins-ci.org/browse/HOSTING-191

I've made the requested changes

@LTegtmeier Please rename the file to match the usual pattern of plugin-, followed by the plugin ID, followed by .yml.


Vendorizing and Releases

Is there a plan to support vendor/ to have consistent build releases? One issue we're struggling with locally is figuring out what version of the go plugin is running. Each developer pulls from tip, because no releases and then potentially gets incompatible go code generated.
Should we just vendorize the proto-gen-c directory? Should I just checkout a specific SHA for golang/protobuf and ensure that every developer is running the same SHA before trying to build proto-gen-c?
Some guidance on how to use this tooling at scale beyond 1 would be appreciated. Most companies are not google and no have monorepos with all their code in a single repository.

As background, we did recently bump the version number of the generated code to fix a deep, common race condition around extensions we were seeing in many packages.  This is the first time we did this, so apologies for the rough edges.
The runtime library expects that your protoc-gen-go binary and generated code are built at the same commit as the runtime library.  We may need to document this assumption better, but we do not intend to bump the version often.  Since protobuf is a library, it would be inappropriate for us to add a vendor/ directory, since binaries are the ones that should "pin" the versions of the libraries they need.

Thanks @zombiezen this helps my understanding. So in order to ensure devs have the correct version I effectively have to do something like this then:
rm -fr $GOPATH/src/github.com/golang/protobuf
go get github.com/golang/protobuf
cd $GOPATH/src/github.com/golang/protobuf/protoc-gen-go
git checkout 0c1f6d65b5a189c2250d10e71a5506f06f9fa0a0
go install

Or you can copy 0c1f6d65b into your project using the vendor/ directory.  There's a variety of tools to help you do this, such as Godeps or govendor.  Then your devs won't have to do the checkout manually, although they may have to ensure their installed protoc-gen-go is the one in the vendor/ directory.
Hope that helps!

Thanks @zombiezen. I am using govendor, this script is basically to ensure that people updating the proto files have the correct tooling.


ARM issue calling prima generate

I tried the instructions on my M1 mac and it failed while building the image (M1 macs can run pre-build x86 images if there would have exist one) while invoke prisma generate. It failed with the following error message:
#10 [deps 5/5] RUN yarn install --frozen
#10 sha256:61ed6171176c251b9f58d3be18dab74335c9ebc4e90f4aeec2e877f2ab2c8124
#10 0.385 yarn install v1.22.5
#10 0.401 info No lockfile found.
#10 0.405 [1/4] Resolving packages...
#10 6.656 warning ics ><EMAIL_ADDRESS>Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
#10 8.196 warning next > native-url ><EMAIL_ADDRESS>The
#10 8.240 warning next > node-libs-browser > url ><EMAIL_ADDRESS>The
#10 9.088 warning next-auth ><EMAIL_ADDRESS>The
#10 25.05 [2/4] Fetching packages...
#10 42.31 info<EMAIL_ADDRESS>The platform "linux" is incompatible with this module.
#10 42.31 info<EMAIL_ADDRESS>is an optional dependency and failed compatibility check. Excluding it from installation.
#10 42.32 [3/4] Linking dependencies...
#10 49.62 [4/4] Building fresh packages...
#10 50.25 success Saved lockfile.
#10 50.26 $ prisma generate
#10 50.49 Error: Unknown binaryTarget linux-arm-openssl-undefined and no custom binaries were provided
#10 50.50 info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
#10 50.50 error Command failed with exit code 1.
#10 ERROR: executor failed running [/bin/sh -c yarn install --frozen]: exit code: 1

You're not the first one to encounter this; https://stackoverflow.com/questions/66530969/docker-compose-up-issue-using-docker-apple-m1 - may be helpful

For now, if you replace FROM node:14-alpine with FROM amd64/node:14-alpine it’ll force Docker to pull the x86 container instead. This will almost certainly fix it.

@jk Were you able to fix your issue with the above feedback?


FreeBSD support - no LWJGL binaries?

So to my surprise we don't appear able to run out of the box on FreeBSD, which it sounds like LWJGL does not include compiled natives for. Or maybe it relates to FreeBSD's ports thing only being at LWJGL 2.9.1 with us recently updating to the final ever LWJGL 2 release 2.9.2 (incidentally 2.9.3 came out three weeks later, heh).

https://github.com/freebsd/freebsd-ports/tree/master/games/lwjgl
http://www.freshports.org/games/lwjgl (no maintainer to bump to 2.9.2)

FreeBSD seems different somehow, as noticed in this 2.9.0 release of LWJGL:
http://forum.lwjgl.org/index.php?topic=4974.0
FreeBSD: Add: Support for compiling - no official binaries.
@fireglow reported this on IRC and did some testing, but we couldn't conclusively pin it on the version - even the prior stable release (46) when we were on 2.9.1 failed.

Exact error reported: http://hastebin.com/aweyuqezob.txt
Hacky workaround for MC: http://hastebin.com/zesiqusabu.sh
Cleaner: https://github.com/freebsd/freebsd-ports/blob/master/games/minecraft-client/files/minecraft-runtime

Possible resolutions:

Downgrade to 2.9.1 ? Seems like it still would take user action to compile 2.9.1 locally via the ports thing
Get the ports thing updated to a newer LWJGL ? Same
Build LWJGL on a FreeBSD droplet ourselves, then somehow ship it with the game? Maybe ideal if that could work and wouldn't violate anything
Something else - this isn't a first and there are lots of hits on Google but I didn't spot any easy fixes in a quirk bit of surfing

Marking as a known issue for now since this one could be tricky :-)

---
Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/8058006-freebsd-support-no-lwjgl-binaries?utm_campaign=plugin&utm_content=tracker%2F5279&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F5279&utm_medium=issues&utm_source=github).

LWJGL 2.9.3 has been released on FreeBSD just recently (Dec 28th). So users should in theory be able to run Terasology on FreeBSD if they install the LWJGL natives themselves and point the game to it right if needed.
https://www.freshports.org/games/lwjgl
It may be something we could help encourage in the launch script or in a help system somewhere. Like if the game crashes from failing to find natives and knows how to retrieve them on the user's OS suggest some instructions or offer to attempt an automated install.
(thanks to greaser|q for the find!)


Optimize layout for desktop mode

Enlarge icons on AppBar
Use larger font for camera status display (F number, etc.)

Released


License?

Adding a license file to the repo would help with knowing about forking and use of this module in commercial settings.

From what I can know based on licensing, I can redistribute this under any Open Source license since JGit is under EPL 1.0.  Is there a preferred license for Community Ignition Modules?  I am leaning toward MIT but I am open to any suggestions.

I am not a lawyer, but I think MIT is fine, and it's what I've used in the past.

I added the MIT license. I will keep adding stuff as I have time or requests for stuff.


every time it shows errror ...why my programs r not running...code is absolutely correct.

Type: Bug
every time it shows errror ...why my programs r not running...code is absolutely correct......my time is wasting on this
VS Code version: Code 1.88.1 (e170252f762678dec6ca2cc69aba1570769a5d39, 2024-04-10T17:41:02.734Z)
OS version: Windows_NT x64 10.0.22621
Modes:

System Info

Item
Value

CPUs
11th Gen Intel(R) Core(TM) i5-11400H @ 2.70GHz (12 x 2688)

GPU Status
2d_canvas: enabledcanvas_oop_rasterization: enabled_ondirect_rendering_display_compositor: disabled_off_okgpu_compositing: enabledmultiple_raster_threads: enabled_onopengl: enabled_onrasterization: enabledraw_draw: disabled_off_okskia_graphite: disabled_offvideo_decode: enabledvideo_encode: enabledvulkan: disabled_offwebgl: enabledwebgl2: enabledwebgpu: enabled

Load (avg)
undefined

Memory (System)
7.73GB (2.49GB free)

Process Argv
--crash-reporter-id 632faaa8-5f57-4869-948e-9465403c7796

Screen Reader
no

VM
0%

Extensions (12)

Extension
Author (truncated)
Version

amiga-debug
Bar
1.7.7

beyond-debug
coo
0.9.15

c-cpp-compile-run
dan
1.0.58

prettier-vscode
esb
10.4.0

vscode-firefox-debug
fir
2.9.10

code-runner
for
0.12.2

atom-keybindings
ms-
3.3.0

cmake-tools
ms-
1.18.27

cpptools
ms-
1.19.9

cpptools-extension-pack
ms-
1.3.0

LiveServer
rit
5.7.9

cmake
twx
0.0.17

(1 theme extensions excluded)

A/B Experiments
vsliv368:30146709
vspor879:30202332
vspor708:30202333
vspor363:30204092
vscoreces:30445986
vscod805:30301674
binariesv615:30325510
vsaa593:30376534
py29gd2263:31024239
c4g48928:30535728
azure-dev_surveyone:30548225
a9j8j154:30646983
962ge761:30959799
pythongtdpath:30769146
welcomedialog:30910333
pythonidxpt:30866567
pythonnoceb:30805159
asynctok:30898717
pythontestfixt:30902429
pythonregdiag2:30936856
pyreplss1:30897532
pythonmypyd1:30879173
pythoncet0:30885854
h48ei257:31000450
pythontbext0:30879054
accentitlementsc:30995553
dsvsc016:30899300
dsvsc017:30899301
dsvsc018:30899302
cppperfnew:31000557
d34g3935:30971562
fegfb526:30981948
bg6jg535:30979843
ccp2r3:30993541
dsvsc020:30976470
pythonait:31006305
666c4381:30973075
gee8j676:31009558
chatpanelc:31018788
dsvsc021:30996838
f3je6385:31013174
pythoncenvpt:31022790

/needsMoreInfo

Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our issue reporting guidelines. Please take the time to review these and update the issue.
Happy Coding!

This issue has been closed automatically because it needs more information and has not had recent activity. See also our issue reporting guidelines.
Happy Coding!


Use enum for Request.ResourceType

since #172 I think we might as well expose this property as an enum
based on https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/puppeteer/index.d.ts#L592
export type ResourceType =
  | "document"
  | "stylesheet"
  | "image"
  | "media"
  | "font"
  | "script"
  | "texttrack"
  | "xhr"
  | "fetch"
  | "eventsource"
  | "websocket"
  | "manifest"
  | "other";

Let's ship it


HDFS-14824. [Dynamometer] Dynamometer in org.apache.hadoop.tools does not output the benchmark results.

I almost just merged https://github.com/linkedin/dynamometer/pull/76, and fixed the license and checkstyle warns.
I tested this PR with my test cluster and the result seems good.
$ hadoop fs -cat dyno/results/part-r-00000
userA,READ       171
userA,WRITE      2772
userB,READ       22
...

:broken_heart: -1 overall

Vote
Subsystem
Runtime
Comment

0
reexec
2141
Docker mode activated.

_ Prechecks _

+1
dupname
0
No case conflicting files found.

+1
@author
0
The patch does not contain any @author tags.

+1
test4tests
0
The patch appears to include 2 new or modified test files.

_ trunk Compile Tests _

0
mvndep
39
Maven dependency ordering for branch

+1
mvninstall
1295
trunk passed

+1
compile
28
trunk passed

+1
checkstyle
21
trunk passed

+1
mvnsite
47
trunk passed

+1
shadedclient
889
branch has no errors when building and testing our client artifacts.

+1
javadoc
41
trunk passed

0
spotbugs
36
Used deprecated FindBugs config; considering switching to SpotBugs.

+1
findbugs
71
trunk passed

_ Patch Compile Tests _

0
mvndep
12
Maven dependency ordering for patch

+1
mvninstall
46
the patch passed

+1
compile
24
the patch passed

+1
javac
24
the patch passed

+1
checkstyle
15
the patch passed

+1
mvnsite
37
the patch passed

+1
whitespace
0
The patch has no whitespace issues.

+1
shadedclient
880
patch has no errors when building and testing our client artifacts.

+1
javadoc
36
the patch passed

+1
findbugs
78
the patch passed

_ Other Tests _

-1
unit
33
hadoop-dynamometer-workload in the patch failed.

-1
unit
22
hadoop-dynamometer-infra in the patch failed.

+1
asflicense
29
The patch does not generate ASF License warnings.

5877

Reason
Tests

Failed junit tests
hadoop.tools.dynamometer.workloadgenerator.TestWorkloadGenerator

hadoop.tools.dynamometer.TestDynamometerInfra

Subsystem
Report/Notes

Docker
Client=19.03.4 Server=19.03.4 base: https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/1/artifact/out/Dockerfile

GITHUB PR
https://github.com/apache/hadoop/pull/1685

Optional Tests
dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient findbugs checkstyle

uname
Linux 29685438c85d 4.15.0-66-generic #75-Ubuntu SMP Tue Oct 1 05:24:09 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Build tool
maven

Personality
personality/hadoop.sh

git revision
trunk / 012756a

Default Java
1.8.0_222

unit
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/1/artifact/out/patch-unit-hadoop-tools_hadoop-dynamometer_hadoop-dynamometer-workload.txt

unit
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/1/artifact/out/patch-unit-hadoop-tools_hadoop-dynamometer_hadoop-dynamometer-infra.txt

Test Results
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/1/testReport/

Max. process+thread count
306 (vs. ulimit of 5500)

modules
C: hadoop-tools/hadoop-dynamometer/hadoop-dynamometer-workload hadoop-tools/hadoop-dynamometer/hadoop-dynamometer-infra U: hadoop-tools/hadoop-dynamometer

Console output
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/1/console

versions
git=2.7.4 maven=3.3.9 findbugs=3.1.0-RC1

Powered by
Apache Yetus 0.10.0 http://yetus.apache.org

This message was automatically generated.

Updated PR. I tested it again with my test cluster and the result is like below.
$ hadoop fs -cat dyno/results/part-r-00000
...
userA,READ,GETFILEINFO,462,6476
userA,READ,LISTSTATUS,441,8821
userA,READ,OPEN,168,2409
...

:broken_heart: -1 overall

Vote
Subsystem
Runtime
Comment

0
reexec
38
Docker mode activated.

_ Prechecks _

+1
dupname
1
No case conflicting files found.

+1
@author
0
The patch does not contain any @author tags.

+1
test4tests
0
The patch appears to include 2 new or modified test files.

_ trunk Compile Tests _

0
mvndep
59
Maven dependency ordering for branch

+1
mvninstall
1114
trunk passed

+1
compile
35
trunk passed

+1
checkstyle
25
trunk passed

+1
mvnsite
96
trunk passed

+1
shadedclient
942
branch has no errors when building and testing our client artifacts.

+1
javadoc
84
trunk passed

0
spotbugs
57
Used deprecated FindBugs config; considering switching to SpotBugs.

+1
findbugs
134
trunk passed

_ Patch Compile Tests _

0
mvndep
15
Maven dependency ordering for patch

+1
mvninstall
90
the patch passed

+1
compile
28
the patch passed

+1
javac
28
the patch passed

+1
checkstyle
17
the patch passed

+1
mvnsite
77
the patch passed

+1
whitespace
0
The patch has no whitespace issues.

+1
shadedclient
818
patch has no errors when building and testing our client artifacts.

+1
javadoc
72
the patch passed

+1
findbugs
142
the patch passed

_ Other Tests _

+1
unit
55
hadoop-dynamometer-workload in the patch passed.

-1
unit
27
hadoop-dynamometer-infra in the patch failed.

-1
unit
82
hadoop-dynamometer in the patch failed.

+1
asflicense
34
The patch does not generate ASF License warnings.

4049

Reason
Tests

Failed junit tests
hadoop.tools.dynamometer.TestDynamometerInfra

hadoop.tools.dynamometer.TestDynamometerInfra

Subsystem
Report/Notes

Docker
Client=19.03.4 Server=19.03.4 base: https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/2/artifact/out/Dockerfile

GITHUB PR
https://github.com/apache/hadoop/pull/1685

Optional Tests
dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient findbugs checkstyle

uname
Linux d5323e292dc8 4.15.0-60-generic #67-Ubuntu SMP Thu Aug 22 16:55:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Build tool
maven

Personality
personality/hadoop.sh

git revision
trunk / e6137d0

Default Java
1.8.0_222

unit
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/2/artifact/out/patch-unit-hadoop-tools_hadoop-dynamometer_hadoop-dynamometer-infra.txt

unit
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/2/artifact/out/patch-unit-hadoop-tools_hadoop-dynamometer.txt

Test Results
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/2/testReport/

Max. process+thread count
418 (vs. ulimit of 5500)

modules
C: hadoop-tools/hadoop-dynamometer/hadoop-dynamometer-workload hadoop-tools/hadoop-dynamometer/hadoop-dynamometer-infra hadoop-tools/hadoop-dynamometer U: hadoop-tools/hadoop-dynamometer

Console output
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/2/console

versions
git=2.7.4 maven=3.3.9 findbugs=3.1.0-RC1

Powered by
Apache Yetus 0.10.0 http://yetus.apache.org

This message was automatically generated.

The failed test seems not to be related.
@xkrogen Could you review it?

Hi @tasanuma , the changes LGTM. The test is failing because 3.1.2 no longer exists on the Apache mirror sites now that 3.1.3 is published. Can you also take care of updating that version here to fix the test? We can use 3.1.3 or 3.2.1. The long term fix of removing this specification is tracked in HDFS-14412.

Thanks for your review, @xkrogen. Updated to 3.1.3.

:confetti_ball: +1 overall

Vote
Subsystem
Runtime
Comment

0
reexec
1784
Docker mode activated.

_ Prechecks _

+1
dupname
1
No case conflicting files found.

+1
@author
0
The patch does not contain any @author tags.

+1
test4tests
0
The patch appears to include 2 new or modified test files.

_ trunk Compile Tests _

0
mvndep
35
Maven dependency ordering for branch

+1
mvninstall
1099
trunk passed

+1
compile
35
trunk passed

+1
checkstyle
24
trunk passed

+1
mvnsite
96
trunk passed

+1
shadedclient
909
branch has no errors when building and testing our client artifacts.

+1
javadoc
82
trunk passed

0
spotbugs
55
Used deprecated FindBugs config; considering switching to SpotBugs.

+1
findbugs
129
trunk passed

_ Patch Compile Tests _

0
mvndep
13
Maven dependency ordering for patch

+1
mvninstall
87
the patch passed

+1
compile
26
the patch passed

+1
javac
26
the patch passed

+1
checkstyle
16
the patch passed

+1
mvnsite
72
the patch passed

+1
whitespace
0
The patch has no whitespace issues.

+1
shadedclient
822
patch has no errors when building and testing our client artifacts.

+1
javadoc
67
the patch passed

+1
findbugs
146
the patch passed

_ Other Tests _

+1
unit
52
hadoop-dynamometer-workload in the patch passed.

+1
unit
482
hadoop-dynamometer-infra in the patch passed.

+1
unit
533
hadoop-dynamometer in the patch passed.

+1
asflicense
31
The patch does not generate ASF License warnings.

6608

Subsystem
Report/Notes

Docker
Client=19.03.4 Server=19.03.4 base: https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/3/artifact/out/Dockerfile

GITHUB PR
https://github.com/apache/hadoop/pull/1685

Optional Tests
dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient findbugs checkstyle

uname
Linux aed26f178d37 4.15.0-60-generic #67-Ubuntu SMP Thu Aug 22 16:55:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Build tool
maven

Personality
personality/hadoop.sh

git revision
trunk / ef9d12d

Default Java
1.8.0_222

Test Results
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/3/testReport/

Max. process+thread count
989 (vs. ulimit of 5500)

modules
C: hadoop-tools/hadoop-dynamometer/hadoop-dynamometer-workload hadoop-tools/hadoop-dynamometer/hadoop-dynamometer-infra hadoop-tools/hadoop-dynamometer U: hadoop-tools/hadoop-dynamometer

Console output
https://builds.apache.org/job/hadoop-multibranch/job/PR-1685/3/console

versions
git=2.7.4 maven=3.3.9 findbugs=3.1.0-RC1

Powered by
Apache Yetus 0.10.0 http://yetus.apache.org

This message was automatically generated.

Thanks @tasanuma !


How to get camera view transform on Hololens2

I open the camera and get MediaFrameReference, then I want to get the camera view transformation matrix.
I used the GUID(0x4E251FA4, 0x830F, 0x4770, 0x85, 0x9A, 0x4B, 0x8D, 0x99, 0xAA, 0x80, 0x9B)
to find the matrix from the MediaFrameReference.Properties,
It works well on Hololens1, but always failed on Hololens2.
I tried many ways to find how to get this matrix, but always failed ,
could you help me to fix the problem? Thank you very much!

文档详细信息
⚠ 请勿编辑此部分。 docs.microsoft.com ➟ GitHub 问题链接必须具有此部分。

ID: bef07a03-4fbb-f4ef-ca3c-359cb9776848
Version Independent ID: 0fd3c7d1-2ab9-677b-a0c9-2e30f65322dd
Content: MediaFrameReference Class (Windows.Media.Capture.Frames) - Windows UWP applications
Content Source: https://cpubwin.visualstudio.com/DefaultCollection/windows-uwp/_git/winrt-api-build?path=%2fwinrt-api-build%2fwindows.media.capture.frames.mediaframereference.yml&version=GBlive&_a=contents
Product: uwp
Technology: winrt-reference
Git Login: drewbatgit
Microsoft Alias: drewbat

The code is as below:
XTERN_GUID(MFSampleExtension_Spatial_CameraViewTransform, 0x4E251FA4, 0x830F, 0x4770, 0x85, 0x9A, 0x4B, 0x8D, 0x99, 0xAA, 0x80, 0x9B);
IPropertyValue^ cameraViewIPropertyValue =
(Windows::Foundation::IPropertyValue^)frame->Properties->Lookup(MFSampleExtension_Spatial_CameraViewTransform);

Hello, this feedback channel is intended to be used exclusively for documentation issues, rather than general developer support, but I reached out to the feature team and received this guidance:
Those attributes are deprecated n HoloLens 2. They are replaced by:
https://docs.microsoft.com/en-us/windows/win32/medfound/mfsampleextension-cameraextrinsics
https://docs.microsoft.com/en-us/windows/win32/medfound/mfsampleextension-pinholecameraintrinsics
Those attributes can be referenced directly by application code using the older COM-based MF APIs, i.e. IMFSample et al. We have code samples that demonstrate how to assemble the raw data to relate a camera frame to an existing SpatialCoordinateSystem tracked by the HMD; see below for the canonical example.
The ”golden path” is to use the Windows.Media.Capture.Frames WinRT API, which does all the integration below for you, and is accessible from C# (modulo normal Unity UWP constraints). Specifically, the extrinsics and intrinsics are exposed via the following properties:
https://docs.microsoft.com/en-us/uwp/api/windows.media.capture.frames.mediaframereference.coordinatesystem
https://docs.microsoft.com/en-us/uwp/api/windows.media.capture.frames.videomediaframe.cameraintrinsics
#include <winrt/windows.perception.spatial.preview.h>
#include <mfapi.h>
#include <mfidl.h>

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Numerics;
using namespace winrt::Windows::Perception;
using namespace winrt::Windows::Perception::Spatial;
using namespace winrt::Windows::Perception::Spatial::Preview;

class CameraFrameLocator
{
public:
    struct CameraFrameLocation
    {
        SpatialCoordinateSystem CoordinateSystem;
        float4x4 CameraViewToCoordinateSytemTransform;
        MFPinholeCameraIntrinsics Intrinsics;
    };

    std::optional<CameraFrameLocation> TryLocateCameraFrame(IMFSample* pSample)
    {
        MFCameraExtrinsics cameraExtrinsics;
        MFPinholeCameraIntrinsics cameraIntrinsics;
        UINT32 sizeCameraExtrinsics = 0;
        UINT32 sizeCameraIntrinsics = 0;
        UINT64 sampleTimeQpc = 0;

        // query sample for calibration and validate
        if (FAILED(pSample->GetUINT64(MFSampleExtension_DeviceTimestamp, &sampleTimeQpc)) ||
            FAILED(pSample->GetBlob(MFSampleExtension_CameraExtrinsics, (UINT8*)& cameraExtrinsics, sizeof(cameraExtrinsics), &sizeCameraExtrinsics)) ||
            FAILED(pSample->GetBlob(MFSampleExtension_PinholeCameraIntrinsics, (UINT8*)& cameraIntrinsics, sizeof(cameraIntrinsics), &sizeCameraIntrinsics)) ||
            (sizeCameraExtrinsics != sizeof(cameraExtrinsics)) ||
            (sizeCameraIntrinsics != sizeof(cameraIntrinsics)) ||
            (cameraExtrinsics.TransformCount == 0))
        {
            return std::nullopt;
        }

        // compute extrinsic transform
        const auto& calibratedTransform = cameraExtrinsics.CalibratedTransforms[0];
        const GUID& dynamicNodeId = calibratedTransform.CalibrationId;
        const float4x4 cameraToDynamicNode =
            make_float4x4_from_quaternion(quaternion{ calibratedTransform.Orientation.x, calibratedTransform.Orientation.y, calibratedTransform.Orientation.z, calibratedTransform.Orientation.w }) *
            make_float4x4_translation(calibratedTransform.Position.x, calibratedTransform.Position.y, calibratedTransform.Position.z);

        // update locator cache for dynamic node
        if (dynamicNodeId != m_currentDynamicNodeId || !m_locator)
        {
            m_locator = SpatialGraphInteropPreview::CreateLocatorForNode(dynamicNodeId);
            if (!m_locator)
            {
                return std::nullopt;
            }

            m_frameOfReference = m_locator.CreateAttachedFrameOfReferenceAtCurrentHeading();
            m_currentDynamicNodeId = dynamicNodeId;
        }

        // locate dynamic node
        auto timestamp = PerceptionTimestampHelper::FromSystemRelativeTargetTime(TimeSpanFrodmQpcTicks(sampleTimeQpc));
        auto coordinateSystem = m_frameOfReference.GetStationaryCoordinateSystemAtTimestamp(timestamp);
        auto location = m_locator.TryLocateAtTimestamp(timestamp, coordinateSystem);
        if (!location)
        {
            return std::nullopt;
        }

        const float4x4 dynamicNodeToCoordinateSystem = make_float4x4_from_quaternion(location.Orientation()) * make_float4x4_translation(location.Position());

        return CameraFrameLocation{ coordinateSystem, cameraToDynamicNode * dynamicNodeToCoordinateSystem, cameraIntrinsics };
    }

private:
    GUID m_currentDynamicNodeId{ GUID_NULL };
    SpatialLocator m_locator{ nullptr };
    SpatialLocatorAttachedFrameOfReference m_frameOfReference{ nullptr };

    // Convert a duration value from a source tick frequency to a destination tick frequency.
    static inline int64_t SourceDurationTicksToDestDurationTicks(int64_t sourceDurationInTicks, int64_t sourceTicksPerSecond, int64_t destTicksPerSecond)
    {
        int64_t whole = (sourceDurationInTicks / sourceTicksPerSecond) * destTicksPerSecond;                          // 'whole' is rounded down in the target time units.
        int64_t part = (sourceDurationInTicks % sourceTicksPerSecond) * destTicksPerSecond / sourceTicksPerSecond;    // 'part' is the remainder in the target time units.
        return whole + part;
    }

    static inline TimeSpan TimeSpanFromQpcTicks(int64_t qpcTicks)
    {
        static const int64_t qpcFrequency = []
        {
            LARGE_INTEGER frequency;
            QueryPerformanceFrequency(&frequency);
            return frequency.QuadPart;
        }();

        return TimeSpan{ SourceDurationTicksToDestDurationTicks(qpcTicks, qpcFrequency, winrt::clock::period::den) / winrt::clock::period::num };
    }
};

Thanks so much for your help!

hello @drewbatgit,
How can this be done in Unity C# as there's no such type as CameraExtrinsics? Could you provide more sources or snippets to understand how to achieve this in Unity?


Hotfix/issue 128

This change is

Current coverage is 56.30% (diff: 100%)

Merging #296 into master will not change coverage

@@             master       #296   diff @@
==========================================
  Files          1969       1969
  Lines        102205     102205
  Methods           0          0
  Messages          0          0
  Branches      12801      12801
==========================================
  Hits          57547      57547
  Misses        41639      41639
  Partials       3019       3019

Powered by Codecov. Last update 84992b9...c8ae82a

Reviewed 1 of 1 files at r1.
Review status: all files reviewed at latest revision, all discussions resolved.

Comments from Reviewable


stop error when splitting to chapters using mp4 format

the main output_file is deleted after splitting into chapters causing an error when trying to tag output_file with cover art

Sorry didn't check that there was already such a merge request. My MR is a bit different, so I leave it here until you decide which one you rather have, feel free to close it.


⚠ GitLab Server has degraded performance

In 149637a, GitLab Server (https://gitlab01.its-telekom.eu) experienced degraded performance:

HTTP code: 200
Response time: 6133 ms

Resolved: GitLab Server performance has improved in 0e93593.


Avoid duplicated element id in explorer tree

This PR fixes #90473
Makes the explorer tree element id unique by appending the corresponding root resource URI.
Another way could be to append the root index to the resource URI
const treeInput = this.tree.getInput()!;
const rootIdx = Array.isArray(treeInput) ? treeInput.indexOf(stat.root) : 0;
return `root${rootIdx}:${stat.resource}`;

This is smart work.
However I would not merge it because:

On VS Code update all expansion state would be lost, since all items would have a new ID
It only fixes a minor issue

I am open to merge this PR in the future. However the cons outweight the pros for me atm.

As per my previous comment we will not merge this. Thus closing this


Libra.org has changed faucet API method from GET to POST

Ref issue: https://community.libra.org/t/minting-service-throws-a-405-error/1541/4

Change method from GET to POST.

Nice, look good to me. Thanks


python3Packages.pandas: 1.4.4 -> 1.5.1

Description of changes

Things done

Built on platform(s)

[ ] x86_64-linux
[ ] aarch64-linux
[ ] x86_64-darwin
[ ] aarch64-darwin

[ ] For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
[ ] Tested, as applicable:

NixOS test(s) (look inside nixos/tests)
and/or package tests
or, for functions and "core" functionality, tests in lib/tests or pkgs/test
made sure NixOS tests are linked to the relevant packages

[ ] Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
[ ] Tested basic functionality of all binary files (usually in ./result/bin/)
22.11 Release Notes (or backporting 22.05 Release notes)

[ ] (Package updates) Added a release notes entry if the change is major or breaking
[ ] (Module updates) Added a release notes entry if the change is significant
[ ] (Module addition) Added a release notes entry if adding a new NixOS module
[ ] (Release notes changes) Ran nixos/doc/manual/md-to-db.sh to update generated release notes

[ ] Fits CONTRIBUTING.md.

Yuck, the build is unreliable (https://github.com/pandas-dev/pandas/issues/47305)

Also, this will need to be retargeted at staging using this technique due to the large number of rebuilds: https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#rebasing-between-branches-ie-from-master-to-staging

@ofborg build python3Packages.fastparquet
Fails for me, aarch64-linux

Sorry for doing the rebase in the codeowners-annoying way. I’ll be more careful next time.

@ofborg build python3.pkgs.pandas

@ofborg eval

Please update to 1.5.2.

@ofborg build python3.pkgs.pandas

@ofborg build python3Packages.fastparquet

@ofborg build python3.pkgs.pandas python3Packages.fastparquet

Cherry-picked into python-updates. #208232


Prepare changelog for 3.0.0

@ferdnyc as you've made the most important change for this upcoming release, feel free to suggest a more verbose version of it because you'll do it better for sure.

Part of me wants to include #365 on the list, just in case it affects anyone, but it's probably too internal to give a concise, coherent explanation in a changelog entry. (I'm already pushing it with #363.)


Incompatible or Mismatched C/C++ Extension Binaries got installed in my system via marketplace in vs code

Does this issue occur when all extensions are disabled?: Yes/No

VS Code Version:
OS Version:

Steps to Reproduce:

/extC

It looks like this is caused by the C extension. Please file the issue to the C extension repository. Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our issue reporting guidelines for more information.
Happy Coding!


Revamp logic for checking that calls get pseudo-assigned to an owning location

The checking that @MustCall obligations are satisfied must ensure that a method or constructor call with non-empty @MustCall type gets assigned to some variable / field that takes ownership of the value.  This PR revamps the logic for this check, moving it out of the ObjectConstructionVisitor and instead leveraging the AssignmentContexts available for CFG nodes.  This change handles more cases in a uniform manner and also sets us up for future enhancements (like leveraging @PolyMustCall / @MustCallChoice annotations).
This is a WIP since it relies on https://github.com/typetools/checker-framework/pull/3891 for proper handling of method calls appearing as a parameter to a constructor call.  The code is currently written against the latest Checker Framework main branch, which required a couple of other changes.  If we use the 3.7.1 CF release, we will get false positives that we will have to ignore until the next release (or we'll have to add some extra temporary hacks / workarounds).  If we code against the CF main branch (assuming https://github.com/typetools/checker-framework/pull/3891 lands), it will get hard to get CI to pass.  I'm not sure of the best way forward.

@msridhar I'm fine with switching to CF head and just letting CI fail for a few weeks. We'll just all have to be diligent that local tests are passing until 3.8.0 is released.

Ok, thanks, @kelloggm.  In that case let's see if https://github.com/typetools/checker-framework/pull/3891 lands soon, and if it does we can switch over to CF head

I think this can be reviewed now, actually.  To test locally, build the CF branch https://github.com/msridhar/checker-framework/tree/assignment-context-for-object-creation and install it to Maven local with ./gradlew deployArtifactsToLocalRepo, and then run the tests here.

Update: https://github.com/typetools/checker-framework/pull/3891 got merged to CF master, so there's no need to use a different CF branch to test anymore


TypeError: get_klines() missing 1 required positional argument: 'self'

Good night!
When I play my code in this part:
klines = get_historical_klines("BNBBTC", Client.KLINE_INTERVAL_1MINUTE, "1 day ago UTC")
the error msg show me this:
TypeError                                 Traceback (most recent call last)
 in
----> 1 klines = get_historical_klines("BNBBTC", Client.KLINE_INTERVAL_1MINUTE, "1 day ago UTC")
 in get_historical_klines(symbol, interval, start_str, end_str)
26             interval=interval,
27             startTime=start_ts,
---> 28             endTime=end_ts,
29
30         )
TypeError: get_klines() missing 1 required positional argument: 'self'
I didn't know how can i fix it. Did anyone can help me, please?
What is argument 'self'?

This is because you're not instantiating client.
client = Client(api_key, api_secret)
after that write
client.get_historical_klines("BNBBTC", Client.KLINE_INTERVAL_1MINUTE, "1 day ago UTC")

Thanks bro!!!

Thnak you that was helpful


Update README.md

Add usage instructions for --template flag

@leomelin Sorry about the slow response. I thought I had added that review comment but apparently I didn't submit the review. The GitHub PR review process is new to me :)

:tada: This PR is included in version 1.4.1 :tada:
The release is available on:

npm package (@latest dist-tag)
GitHub release

Your semantic-release bot :package::rocket:


feat: Add initial RSS feed for news

Summary
I'm sorry this took me so long to get back to 🙈
Currently, This feature adds a basic RSS2 feed at {host}/rss.xml. It only grabs the latest 10 items, so the feed won't get too big. In order to be DRY, I exported & used some methods from ./scripts/news.mjs. If we wanted to get fancier/simpler in the future, we could add frontmatter to the news files & even work with excerpts (similar to .vitepress/genFeed.ts in vuejs/blog).
Reference(s)

Relates to #8.

Screenshot(s)

Feed viewed with Feed Preview Extension

@cyberalien, would love your input on this when you get a chance. Thank you!

Sorry for delay. Checking it now.
First issue is adding exports to scripts/news.mjs. That should never be done. That's a full script, not collection of functions that can be imported, by using functions from it you are running that script when its not supposed to be ran. I'll fix that.

No more issues, everything else looks good.
Merged.
Thanks a lot for adding rss feed!