profile
viewpoint

harfbuzz/harfbuzz 1673

HarfBuzz text shaping engine

Frozen-Flask/Frozen-Flask 660

Freezes a Flask application into a set of static files.

binast/binjs-ref 392

Reference implementation for the JavaScript Binary AST format

rust-threadpool/rust-threadpool 340

A very simple thread pool for parallel task execution

kuchiki-rs/kuchiki 312

(朽木) HTML/XML tree manipulation library for Rust

linebender/skribo 269

A Rust library for low-level text layout.

Flask-FlatPages/Flask-FlatPages 239

Provides flat static pages to a Flask application

lifthrasiir/rust-encoding 216

Character encoding support for Rust

Kozea/cairocffi 178

CFFI-based cairo bindings for Python.

Kozea/Flask-WeasyPrint 105

Make PDF in your Flask app with WeasyPrint

pull request commentrust-lang/rust

Package more llvm-* tools in the rust-dev component, for run-make-fulldeps tests

I believe this is ready for review and landing

SimonSapin

comment created time in a day

push eventSimonSapin/rust

Simon Sapin

commit sha 99f99ca7ab34f2c3514291d3565d767d57e04081

Make users of `download-ci-llvm` download a new version

view details

push time in a day

pull request commentrust-lang/rust

Package more llvm-* tools in the rust-dev component, for run-make-fulldeps tests

Sure, what would be a good location?

SimonSapin

comment created time in 2 days

pull request commentrust-lang/rust

Package more llvm-* tools in the rust-dev component, for run-make-fulldeps tests

Alright, ./x.py test src/test/run-make-fulldeps now suceeds with download-ci-llvm = "if-available" if I hard-code this try build instead of this:

https://github.com/rust-lang/rust/blob/554633534c550d20715e5e1576702b1f035586ad/src/bootstrap/bootstrap.py#L435-L439

But if we land this PR as-is, that logic will still pick the last bors commit that touched the LLVM submodule which for now is before this PR and so does not have the extra tools.

SimonSapin

comment created time in 2 days

pull request commentrust-lang/rust

Package more llvm-* tools in the rust-dev component, for run-make-fulldeps tests

With some more tools…

@bors try

SimonSapin

comment created time in 2 days

push eventSimonSapin/rust

Simon Sapin

commit sha bc3dbc62d6882b32da646aff8c17f5d74d7c5a43

Package more llvm-* tools in the rust-dev component, for run-make-fulldeps tests Fixes https://github.com/rust-lang/rust/issues/78110

view details

push time in 2 days

create barnchSimonSapin/rust

branch : ar

created branch time in 2 days

issue commentrust-lang/rust

"llvm-ar: No such file or directory" in run-make-fulldeps tests with download-ci-llvm

@mati865 I’ll find out! I’ve already started a try build with just ar: https://github.com/rust-lang/rust/pull/78131

@Mark-Simulacrum I can temporarily hard-code llvm_sha in src/bootstrap/bootstrap.py for the purpose of testing, but for everyone else the logic is still picking the last commit that touched the src/llvm-project submodule, which after https://github.com/rust-lang/rust/pull/78131 lands will still be some commit that does not include https://github.com/rust-lang/rust/pull/78131.

Would it make sense to have a "timestamp-ish" file, and pick the last commit that touched either the submodule or that file? That would only be useful until the next LLVM update, though. (Unless we need to tweak thepackaging of the rust-dev component again.)

SimonSapin

comment created time in 2 days

pull request commentrust-lang/rust

Package llvm-ar binary in the rust-dev component

I’ll test this as suggested in https://github.com/rust-lang/rust/issues/78110#issuecomment-712401625

@bors try

SimonSapin

comment created time in 2 days

PR opened rust-lang/rust

Package llvm-ar binary in the rust-dev component

Fixes https://github.com/rust-lang/rust/issues/78110

+3 -2

0 comment

1 changed file

pr created time in 2 days

issue commentrust-lang/rust

"llvm-ar: No such file or directory" in run-make-fulldeps tests with download-ci-llvm

@Mark-Simulacrum I can make a patch adding a couple lines for llvm-ar like the ones there for llvm-config, but can I test it without landing it and waiting for the next Nightly?

(I assume testing locally involves compiling LLVM, so I might wait to do that until I have access again to a many-cores desktop rather than just my laptop.)

SimonSapin

comment created time in 2 days

issue openedrust-lang/rust

"llvm-ar: No such file or directory" in run-make-fulldeps tests with download-ci-llvm

I recently added profile = "compiler" to config.toml in my local repository. In particular, this enables:

[llvm]
download-ci-llvm = "if-available"

When running the full test suite with ./x.py test I get three errors similar to this:

---- [run-make] run-make-fulldeps/cross-lang-lto stdout ----

error: make failed
status: exit code: 2
command: "make"
stdout:
------------------------------------------
LD_LIBRARY_PATH="/home/simon/projects/rust/build/x86_64-unknown-linux-gnu/test/run-make-fulldeps/cross-lang-lto/cross-lang-lto:/home/simon/projects/rust/build/x86_64-unknown-linux-gnu/stage1/lib:/home/simon/projects/rust/build/x86_64-unknown-linux-gnu/stage0-bootstrap-tools/x86_64-unknown-linux-gnu/release/deps:/home/simon/projects/rust/build/x86_64-unknown-linux-gnu/stage0/lib" '/home/simon/projects/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc' --out-dir /home/simon/projects/rust/build/x86_64-unknown-linux-gnu/test/run-make-fulldeps/cross-lang-lto/cross-lang-lto -L /home/simon/projects/rust/build/x86_64-unknown-linux-gnu/test/run-make-fulldeps/cross-lang-lto/cross-lang-lto  lib.rs -Copt-level=2 -Clinker-plugin-lto -Ccodegen-units=1 --crate-type=staticlib -o /home/simon/projects/rust/build/x86_64-unknown-linux-gnu/test/run-make-fulldeps/cross-lang-lto/cross-lang-lto/liblib.a
(cd /home/simon/projects/rust/build/x86_64-unknown-linux-gnu/test/run-make-fulldeps/cross-lang-lto/cross-lang-lto; rm -f ./*.o; "/home/simon/projects/rust/build/x86_64-unknown-linux-gnu/ci-llvm/bin"/llvm-ar x  liblib.a)

------------------------------------------
stderr:
------------------------------------------
warning: ignoring --out-dir flag due to -o flag

warning: 1 warning emitted

/bin/sh: /home/simon/projects/rust/build/x86_64-unknown-linux-gnu/ci-llvm/bin/llvm-ar: No such file or directory
make: *** [Makefile:23: staticlib] Error 127

Maybe the packaging of LLVM downloaded from CI needs to be fixed to include llvm-ar?

created time in 2 days

issue closedservo/servo

Audit Servo for dependencies on mozilla services

We need to audit servo for any dependencies on mozilla services, and decide what to do with each of them.

closed time in 4 days

asajeffrey

issue commentservo/servo

Audit Servo for dependencies on mozilla services

Closing, let’s move to https://github.com/servo/project/issues/15 and https://github.com/servo/project/issues/25

asajeffrey

comment created time in 4 days

issue commentkuchiki-rs/kuchiki

Question on `select` and its inclusive nature

https://docs.rs/kuchiki/0.8.1/src/kuchiki/iter.rs.html#159-161 shows that NodeRef::select is implemented as:

        self.inclusive_descendants().select(selectors)

Try x.descendants().select("div") instead? https://docs.rs/kuchiki/0.8.1/kuchiki/iter/struct.Descendants.html#method.select

hipstermojo

comment created time in 6 days

issue commentw3c/csswg-drafts

[css-sizing-3][css-images-3] Distinguish intrinsic size's two definitions with two terms

Natural size sounds good to me, and consistency with HTML seems worthwhile.

HTML defines natural size as density-corrected. I think we want that.

When an img element has a current pixel density that is not 1.0, the element's image data must be treated as if its resolution, in device pixels per CSS pixels, was the current pixel density. The image's density-corrected intrinsic width and height are the intrinsic width and height after taking into account the current pixel density.

This is based on a css-images definition, so changing that may require coordination with HTML.

The density in question is from srcset (through update image data and select an image source algorithms).

fantasai

comment created time in 8 days

issue commentservo/servo

Rename this to zinc

And https://github.com/hackndev/zinc / https://zinc.rs/ already used that name even though it’s not active anymore.

larsenv

comment created time in 10 days

issue commentrust-lang/rust

Tracking Issue for `num_as_ne_bytes` feature

Ad discussed starting in https://github.com/rust-lang/rust/issues/64464#issuecomment-705786778 I’m not convinced this feature carries its weight to be included in the standard library, given that to_ne_bytes also exists.

hch12907

comment created time in 10 days

issue commentrust-lang/rust

as_ne_bytes for primitive types

If a library wants to be general-purpose enough to expose such a trait, can’t it afford to do the unsafe conversion by itself? Does this really need to be in the standard library?

hch12907

comment created time in 11 days

issue commentrust-lang/rust

Tracking isuse for `handle_alloc_error` defaulting to panic (for no_std + liballoc)

Since the implementation PR points here as the tracking issue I’ve labelled it accordingly and added a before-stabilization checklist in the description.


Unwinding is pretty inherent to this proposal. But yeah it would be nice if we could somehow skip emitting those landing pad in the common case where the std crate is know to be in the dependency graph (since it overrides the default handler with one that does not unwind). Though that would only help if the relevant code paths of the alloc crate are inlined or maybe LTO’ed…

SimonSapin

comment created time in 13 days

issue commentrust-lang/rust

Make `handle_alloc_error` default to panic (for no_std + liballoc)

I feel another FCP is not necessary, but some feedback from a "real" project (larger than a synthetic test case, perhaps embedded running on actual hardware?) trying this out would be good before stabilization.

SimonSapin

comment created time in 13 days

issue commentrust-lang/rust

as_ne_bytes for primitive types

Why is a borrow useful? Can’t the calling code assign the result of to_*e_bytes to a local variable and borrow that?

hch12907

comment created time in 13 days

Pull request review commentrust-lang/rfcs

[RFC] A new stack-based vector

+- Feature Name: `stack_based_vec`+- Start Date: 2020-09-27+- RFC PR: [rust-lang/rfcs#2990](https://github.com/rust-lang/rfcs/pull/2990)+- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)++# Summary+[summary]: #summary++This RFC, which depends and takes advantage of the upcoming stabilization of constant generics (min_const_generics), tries to propose the creation of a new "growable" vector named `ArrayVec` that manages stack memory and can be seen as an alternative for the built-in structure that handles heap-allocated memory, aka `alloc::vec::Vec<T>`.++# Motivation+[motivation]: #motivation++`core::collections::ArrayVec<T>` has several use-cases and should be conveniently added into the standard library due to its importance.++### Unification++There are a lot of different crates about the subject that tries to do roughly the same thing, a centralized implementation would stop the current fragmentation.++### Optimization++Stack-based allocation is generally faster than heap-based allocation and can be used as an optimization in places that otherwise would have to call an allocator. Some resource-constrained embedded devices can also benefit from it.++### Building block++Just like `Vec`, `ArrayVec` is also a primitive vector where high-level structures can use it as a building block. For example, a stack-based matrix or binary heap.++### Useful in the real world++`arrayvec` is one of the most downloaded project of `crates.io` and is used by thousand of projects, including Rustc itself.+++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation++`ArrayVec` is a container that encapsulates fixed size buffers. ++```rust+let mut v: ArrayVec<i32, 4> = ArrayVec::new();+let _ = v.push(1);+let _ = v.push(2);++assert_eq!(v.len(), 2);+assert_eq!(v[0], 1);++assert_eq!(v.pop(), Some(2));+assert_eq!(v.len(), 1);++v[0] = 7;+assert_eq!(v[0], 7);++v.extend([1, 2, 3].iter().copied());++for element in &v {+    println!("{}", element);+}+assert_eq!(v, [7, 1, 2, 3]);+```++Instead of relying on a heap-allocator, stack-based memory area is added and removed on-demand in a last-in-first-out (LIFO) order according to the calling workflow of a program. `ArrayVec` takes advantage of this predictable behavior to reserve an exactly amount of uninitialized bytes up-front and these bytes form a buffer where elements can be included dynamically.++```rust+// `array_vec` can store up to 64 elements+let mut array_vec: ArrayVec<i32, 64> = ArrayVec::new();+```++Of course, fixed buffers lead to inflexibility because unlike `Vec`, the underlying capacity can not expand at run-time and there will never be more than 64 elements in the above example.++```rust+// This vector can store up to 0 elements, therefore, nothing at all+let mut array_vec: ArrayVec<i32, 0> = ArrayVec::new();+let push_result = array_vec.push(1);+// Ooppss... Our push operation wasn't successful+assert!(push_result.is_err());+```++A good question is: Should I use `core::collections::ArrayVec<T>` or `alloc::collections::Vec<T>`? Well, `Vec` is already good enough for most situations while stack allocation usually shines for small sizes.++* Do you have a known upper bound?++* How much memory are you going to allocate for your program? The default values of `RUST_MIN_STACK` or `ulimit -s` might not be enough.++* Are you using nested `Vec`s? `Vec<ArrayVec<T, N>>` might be better than `Vec<Vec<T>>`.++Each use-case is different and should be pondered individually. In case of doubt, stick with `Vec`.++For a more technical overview, take a look at the following operations:++```rust+// `array_vec` has a pre-allocated memory of 2048 bits (32 * 64) that can store up+// to 64 decimals.+let mut array_vec: ArrayVec<i32, 64> = ArrayVec::new();++// Although reserved, there isn't anything explicitly stored yet+assert_eq!(array_vec.len(), 0);++// Initializes the first 32 bits with a simple '1' decimal or+// 00000000 00000000 00000000 00000001 bits+array_vec.push(1);++// Our vector memory is now split into a 32/2016 pair of initialized and+// uninitialized memory respectively+assert_eq!(array_vec.len(), 1);+```++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++`ArrayVec` is a contiguous memory block where elements can be collected, therefore, a collection by definition and even though `core::collections` doesn't exist, it is the most natural module placement.++The API basically mimics most of the current `Vec` surface with some tweaks to manage capacity.++Notably, these tweaked methods are fallible versions of some well-known functions like `push` that will return `Result` instead of panicking at run-time. Since the upper capacity bound is known at compile-time, the compiler is likely going to remove most of the conditional bounding checking.++```rust+// Please, bare in mind that these methods are simply suggestions. Discussions about the+// API should probably take place elsewhere.++pub struct ArrayVec<T, const N: usize> {+    data: MaybeUninit<[T; N]>,+    len: usize,

"Probably" is not a great fit for the standard library.

Ideally we’d use specialization of some private trait with an associated type to choose the smallest integer type that can represent 0..=N. However it looks like boolean conditions based on const parameters can not be used in where clauses today, and I don’t know if supporting that is planned at all. And this would only help where align_of::<T>() is less than size_of::<usize>().

c410-f3r

comment created time in 14 days

PullRequestReviewEvent

pull request commentrust-lang/rfcs

RFC: Structural Records

What does row-type polymorphism mean?

Having an enum variant with one positional field whose type is a structural record (a.k.a. anonymous struct) would not be the same as an enum variant with multiple named fields.

Centril

comment created time in 15 days

pull request commentrust-lang/rfcs

RFC: Structural Records

@wongjiahau There is not directly¹ a runtime performance issue, it’s only the convenience in code you can write. To adapt an example from your code:

pub enum Type {
    Union(UnionType),
    // Other variants…
}

pub struct UnionType {
    pub span: Span,
    pub types: Vec<Type>,
}

pub fn do_something_with_union(foo: &mut UnionType) {
    // …
}

You could remove the structs used in enum variants and used named fields directly in the variants instead:

pub enum Type {
    Union {
        span: Span,
        types: Vec<Type>,
    },
    // Other variants…
}

But there there is no type anymore that represents a union. So how would you write the do_something_with_union function? You could pass &mut Span and &mut Vec<Type> separately but that doesn’t feel great to me. And it gets worse if you have more than two fields. But maybe you don’t have any function like do_something_with_union so that’s not a problem.


¹ There can be differences in memory layout that may have some effect on performance. Passing many parameters to a function instead of one reference to a struct can use more registers or stack space (unless the function is inlined…). On the other hand making that reference possible may increase size_of because of field alignment. For example struct Foo(u32, u8) will typically occupy 8 bytes and have 4-byte alignment, so enum Bar { Foo(Foo), Other(u16) } will have its tag/discriminant padded to 4 bytes to respect alignment, bringing the enum to 12 bytes. Whereas enum Baz { Foo(u32, u8), Other(u16) } can re-order its fields and pack the u8 field together with the enum tag and keep the enum’s size_of at 8 bytes.

Centril

comment created time in 15 days

pull request commentrust-lang/rfcs

RFC: Structural Records

This is not new. Conversely structs can also have anonymous fields: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types

A downside of having an enum variant with multiple named fields directly (instead of one field that is a struct) is that you can’t manipulate as a single value (or reference) those fields together, known to be in that particular variant.

Centril

comment created time in 15 days

issue commentkuchiki-rs/kuchiki

Question: Equivalent of innerHTML method

.innerHTML in the DOM likely has similar (in)efficiency as .serialize() in Kuchiki. Unless some browsers silently cache it, but I don’t know if accessing it repeatedly without changing that subtree is common enough that such a cache would be worth the memory usage.

hipstermojo

comment created time in 15 days

pull request commentservo/rust-url

remove dependency on `matches` crate - `matches!` is now in Rust stable

No worries! And yeah that sounds like a good plan.

utkarshkukreti

comment created time in 17 days

pull request commentservo/rust-url

remove dependency on `matches` crate - `matches!` is now in Rust stable

This dependency is very small, removing it does not seem worth incrementing the minimum Rust version to me.

utkarshkukreti

comment created time in 18 days

issue commentrust-lang/wg-allocators

Rename LayoutErr to LayoutError

If and when this WG and the Libs team agree on a new name, I think there is no need to mess with #[unstable] items and the new name can be stable as soon as it’s added.

As to deprecation warnings, if we want them emitted we should use the since attribute to make it start two release cycles or more after the release that adds the new name (the current version of Nightly at the time of landing). That way the new name has reached the Stable channel when the Nightly channel starts warning. There is no need to wait for that cycle to add the attribute. That’s what since in rustc_deprecated is for, we can set it in the future.

However another option is to not emit any deprecation warning, and only soft-deprecate the old name in docs. What do we really gain by nudging existing code bases to actively migrate to the new name?

However I personally don’t feel strongly that the naming consistency is worth bothering in the first place. Not renaming at all is also an option.

exrook

comment created time in 20 days

PR closed servo/servo

READ.md spam

Fantastic work

<!-- Please describe your changes on the following line: -->


<!-- Thank you for contributing to Servo! Please replace each [ ] by [X] when the step is complete, and replace ___ with appropriate data: -->

  • [ ] ./mach build -d does not report any errors
  • [ ] ./mach test-tidy does not report any errors
  • [ ] These changes fix #___ (GitHub issue number if applicable)

<!-- Either: -->

  • [ ] There are tests for these changes OR
  • [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

+1 -1

0 comment

1 changed file

Tush6571

pr closed time in 20 days

pull request commentrust-lang/rust

Implement Make `handle_alloc_error` default to panic (for no_std + liballoc)

@bors r=Amanieu

haraldh

comment created time in 21 days

pull request commentrust-lang/rust

Split core/str/mod.rs to smaller files

@bjorn3 Is that number really due to this PR? It looks like that benchmark has been oscillating between two results, recently:

image

lzutao

comment created time in 21 days

pull request commentrust-lang/rust

Implement Make `handle_alloc_error` default to panic (for no_std + liballoc)

The new libc-based test fails to compile on Windows: https://github.com/rust-lang-ci/rust/runs/1189329107#step:23:17312

haraldh

comment created time in 21 days

issue commentkuchiki-rs/kuchiki

Question on naming conventions of ids starting with a number.

The syntax or restrictions on HTML id attributes are entirely separate from those of CSS ID selectors.

The former can have HTML escape sequences, so the ID value for <p id="&quot;"> is one double-quote character.

The latter relies is # followed by a CSS identifier, which indeed cannot start by an ASCII digit. However it is possible to write a CSS identifier that represents a value that starts with a digit, by escaping it.

CSS escape sequences are a backslash followed by either the character to be escaped, or by a sequence of hexadecimal digits representing the Unicode code point (followed by an optional space, to separate following digits that are not meant to be part of the escape sequence). To resolve ambiguities, hex digits can only be escaped as their code point value.

TL;DR: to select <p id="1">, use select_first("p#\31") since U+0031 is the ASCII digit 1.

More details: https://mathiasbynens.be/notes/css-escapes

hipstermojo

comment created time in 22 days

Pull request review commentrust-lang/rfcs

[RFC] A new stack-based vector

 Of course, fixed buffers lead to some inflexibility because unlike `Vec`, the un # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -`ArrayVec` is a contiguous memory block where elements can be collected, threfore, a collection by definition and even though `core::collections` doesn't exist, it is the most natural module placement.+`ArrayVec` is a contiguous memory block where elements can be collected, therefore, a collection by definition and even though `core::collections` doesn't exist, it is the most natural module placement. -The API basically mimics most of the current `Vec` surface with some tweaks and additional methods to manage capacity. Notably, these additional methods are fallible versions of some well-known functions like `insert` that will return `Result` instead of panicking at run-time.+The API basically mimics most of the current `Vec` surface with some tweaks to manage capacity. Notably, these additional methods are fallible versions of some well-known functions like `push` that will return `Result` instead of panicking at run-time.  ```rust // core::collections  pub struct ArrayVec<T, const N: usize> {     data: MaybeUninit<[T; N]>,-    len: usize+    len: usize, }  impl<T, const N: usize> ArrayVec<T, N> {     // Constructors -    pub unsafe fn from_raw_parts(_ptr: *mut T, _len: usize) -> Self;+    #[inline]+    pub fn from_array(array: [T; N]) -> Self;

Do or will eventually const generics allow something like impl<T, const N: usize, const M: usize> impl From<[T; M]> for ArrayVec<T, N> where {M <= N}?

c410-f3r

comment created time in 24 days

PullRequestReviewEvent

pull request commentrust-lang/rust

add `array::FillError` similar to `array::IntoIter`

For what it’s worth I think the design of SmallVec a.k.a. DynVec is much less obvious. (For example using an actual enum means having padding for the discriminant + field alignment, making the container larger than it really needs to be.) I’d rather not tie it together with ArrayVec.

lcnr

comment created time in a month

pull request commentrust-lang/rust

add `array::FillError` similar to `array::IntoIter`

I think a const-generics-based ArrayVec totally makes sense in the standard library, and I agree with @ollie27 this is pretty much it except for the name.

crates.io has multiple ArrayVec-like libraries that have explored the design space, so I’m not sure an RFC would help a lot here as I don’t expect new ideas to come out of more design discussion.

lcnr

comment created time in a month

issue commentservo/servo

Logo proposal

Ideally SVG, since this looks extremely vector-friendly.

VAS

comment created time in a month

pull request commentrust-lang/rust

add array::from_ref

Good point @emilazy.

@lcnr, could you make the change in this PR? r=me with that.

lcnr

comment created time in a month

pull request commentrust-lang/rust

add array::from_ref

This is new unstable safe API that would be very easy to re-implement, but require unsafe. It is rather niche, but follows the precedent of similar functions in std::slice. At least one person asked about exactly this: https://www.reddit.com/r/rust/comments/ixqzkf/are_there_any_gotchas_to_converting_t_into_t_1/

@rust-lang/libs Does anyone feel this should not be merged and eventually stabilized?

lcnr

comment created time in a month

Pull request review commentrust-lang/rust

add array::from_ref

 mod iter; #[unstable(feature = "array_value_iter", issue = "65798")] pub use iter::IntoIter; +/// Converts a reference to `T` into a reference to an array of length 1 (without copying).+#[unstable(feature = "array_from_ref", issue = "none")]

Please file a tracking issue and replace none here and on from_mut below before merging.

lcnr

comment created time in a month

PullRequestReviewEvent

pull request commentrust-lang/rfcs

Edition 2021 and beyond

These changes look good. Thanks!

Having retrospective blog posts on the same cadence and schedule as compiler mode releases sounds ok to me, as long as we’re careful in the messaging to not call "part of the 20XX edition" language features that don’t require a changing the compiler mode.

(I’m still not thrilled about using the same term for two different concepts, and still don’t understand the apparent desire to actively keep it that way, but oh well.)


This part of the RFC is unchanged:

We will roll out an edition regardless of whether there are breaking changes.

Does that also imply "regardless of whether there are idiom lint changes"? Would we possibly introduce for example edition = "2024" that behaves exactly the same as edition = "2021"?

nikomatsakis

comment created time in a month

Pull request review commentrust-lang/rfcs

RFC 2582: fix implicit auto-deref of raw pointers

 This has the side-effect of being able to entirely remove reference-to-pointer-*  ```rust let x: *mut Struct = NonNull::dangling().as_ptr();-let field: *mut Field = &mut x.field;+let field: *mut Field = &mut (*x).field; ```  The lint as described in this RFC would nudge people to instead write  ```rust let x: *mut Struct = NonNull::dangling().as_ptr();-let field: *mut Field = &raw mut x.field;+let field: *mut Field = &raw mut (x*).field;
let field: *mut Field = &raw mut (*x).field;
RalfJung

comment created time in a month

PullRequestReviewEvent

issue commentrust-lang/rust

Tracking issue for RFC 2582, `&raw [mut | const] $place` (raw_ref_op)

Now I am really confused, because this is the exact opposite of what you just asked for! If we want to make this safe, we have to make * special when used below &raw. And you just said you were rather opposed to that.

I thought this was what the RFC proposes, so it looks like I deeply misunderstand it :/

Centril

comment created time in a month

issue commentrust-lang/rust

Tracking Issue for raw_ref_macros

The aforementioned RFC proposes a new primitive syntax for these macros. However, we are not yet ready to commit to a stable syntax for these operations -- but we still would like to expose this ability to stable code.

Stabilizing these macros but keeping the language level syntax unstable does allow us to change the exact sigils used to spell &raw, but it does lock us into the design of RFC 2582 that focuses on avoiding the need for & / &mut operators. I’m sorry to say it this late in the process but as commented in https://github.com/rust-lang/rust/issues/64490#issuecomment-695769136 I feel that we should instead consider designs that focus on avoiding the * operator to "dereference" pointers that may not point to valid memory.

@rfcbot concern references to fields is not the problem, dereferencing raw pointers is

RalfJung

comment created time in a month

issue commentrust-lang/rust

Tracking issue for RFC 2582, `&raw [mut | const] $place` (raw_ref_op)

With this RFC’s addition to the language, dereferencing with * a raw pointer to invalid memory may or may not be UB, depending on whether the expression eventually also uses &raw.

By the way, shouldn’t raw pointer field projection always be safe? &raw mut (*dangling).1 requires an unsafe block in current Nightly.

Centril

comment created time in a month

issue commentrust-lang/rust

Tracking issue for RFC 2582, `&raw [mut | const] $place` (raw_ref_op)

The problem is that this means the semantics of * differ depending on the syntactic context, which seems rather tricky and could be surprising to programmers -- in particular when that context is introduced implicitly by the compiler (through auto-ref).

I’m not sure if by "this" you mean a future possibility, but I think the RFC as-is introduces exactly that problem.

Consider this code with UB:

struct A(u8, i32);

let dangling: *mut A = std::ptr::NonNull::dangling().as_ptr();
let field_ref: &i32 = unsafe { &(*dangling).1 };

The RFC seems to be written on the premise that problematic part of this code is the reference-creating operator &, and proposes a new operator that can be used instead. However that does not match my mental model at all. My understanding of raw pointers in current stable Rust is that the dereference operator * is the only source of unsafety / potential UB. Using it requires the raw pointer to point to valid memory. Indeed, copying a field without using the reference-creating operator causes just as much UB:

struct A(u8, i32);

let dangling: *mut A = std::ptr::NonNull::dangling().as_ptr();
let copied_field: i32 = unsafe { (*dangling).1 };

With this RFC’s addition to the language, dereferencing with * a raw pointer to invalid memory may or may not be UB, depending on whether the expression eventually also uses &raw. This makes the unsafety of raw pointers harder to reason about. I’m sorry to only say it this late (the RFC is already accepted), but I feel strongly that this is an important enough flaw that we should consider alternative designs that focus on avoiding the * operator instead of avoiding the & or &mut operator.

If we need to do projection of a raw pointer to a struct to a raw pointer to a field of that struct, could we have an operator doing exactly that? Strawman not fully thought through:

struct A(u8, i32);

let dangling: *mut A = std::ptr::NonNull::dangling().as_ptr();
let field_ptr: *mut i32 = dangling->1;

Aside, from the RFC:

If one wants to avoid creating a reference to uninitialized data (which might or might not become part of the invariant that must be always upheld), it is also currently not possible to create a raw pointer to a field of an uninitialized struct: again, &mut uninit.field as *mut _ would create an intermediate reference to uninitialized data.

But what is the type of uninit in that expression? Presumably it is not SomeStruct but something like *mut SomeStruct from MaybeUninit::as_mut_ptr, otherwise the example would have UB before we even get to the given code. So that example might be missing an operator for dereferencing a raw pointer: &mut (*uninit).field as *mut _.

Centril

comment created time in a month

PR closed servo/servo

[Do not merge] CI testing
+1 -0

4 comments

1 changed file

SimonSapin

pr closed time in a month

pull request commentrust-lang/rust

Split `core/num/mod.rs` to smaller mods

@bors r+

lzutao

comment created time in a month

pull request commentrust-lang/rust

Split `core/num/mod.rs` to smaller mods

Looks good, thanks!

@bors r+

lzutao

comment created time in a month

pull request commentservo/servo

[Do not merge] CI testing

On the last 4 PR that merged, the start-to-end time for WPT on mac (compilation not included) has been 34, 28, 29, and 29 minutes. This run with 4 workers instead of 9 took 56 minutes. It looks like chunking works predictably and the effect of removing workers is close to linear.

SimonSapin

comment created time in a month

pull request commentservo/taskcluster-config

Don’t keep a Windows worker running on EC2 when CI is idle.

I’ve applied the reverse change (setting minCapacity back to 1) for now and will look into this more tomorrow.

SimonSapin

comment created time in a month

pull request commentservo/servo

[Do not merge] CI testing

I’ve temporarily disabled 5 out of the 9 macOS workers we have on CI, leaving 4 of them active. Let’s see how that affects cycle time with no other change.

@bors try=wpt-mac

SimonSapin

comment created time in a month

PR opened servo/servo

[Do not merge] CI testing
+1 -0

0 comment

1 changed file

pr created time in a month

create barnchservo/servo

branch : SimonSapin-patch-1

created branch time in a month

push eventservo/taskcluster-config

Simon Sapin

commit sha 2a86398f205f2619d994a8838f1f3dc067c09789

Don’t keep a Windows worker running on EC2 when CI is idle. This adds latency (EC2 provisioning time + boot time) but reduces cost.

view details

push time in a month

delete branch servo/taskcluster-config

delete branch : windows-min-capacity

delete time in a month

PR merged servo/taskcluster-config

Don’t keep a Windows worker running on EC2 when CI is idle.

This adds latency (EC2 provisioning time + boot time) but reduces cost.

+1 -1

1 comment

1 changed file

SimonSapin

pr closed time in a month

pull request commentservo/taskcluster-config

Don’t keep a Windows worker running on EC2 when CI is idle.

I’ve already applied this config change.

SimonSapin

comment created time in a month

PR opened servo/taskcluster-config

Don’t keep a Windows worker running on EC2 when CI is idle.

This adds latency (EC2 provisioning time + boot time) but reduces cost.

+1 -1

0 comment

1 changed file

pr created time in a month

create barnchservo/taskcluster-config

branch : windows-min-capacity

created branch time in a month

issue commentservo/rust-url

WASM file size

Yes, using the browser’s URL parsing is what I had in mind:

https://url.spec.whatwg.org/#api https://docs.rs/web-sys/0.3.45/web_sys/struct.Url.html

MartinKavik

comment created time in a month

issue commentservo/rust-url

WASM file size

Libraries that use rust-url could have a switch that makes them use web-sys instead, but I feel that within rust-url itself is not the right place for such a switch.

MartinKavik

comment created time in a month

pull request commentrust-lang/rfcs

[RFC]: Portable SIMD Libs Project Group

Right, if SLEEF is involved then APIs that depend on it should be in libstd but not libcore.

KodrAus

comment created time in a month

push eventSimonSapin/rfcs

Simon Sapin

commit sha 04ba25fbca87657077653f52b4b051396996c749

Pointer metadata RFC: the Drop impl example written two years ago appears broken

view details

push time in a month

Pull request review commentrust-lang/rfcs

RFC: Pointer metadata & VTable

+- Feature Name: `ptr-meta`+- Start Date: 2018-10-26+- RFC PR:+- Rust Issue:++# Summary+[summary]: #summary++Add generic APIs that allow manipulating the metadata of fat pointers:++* Naming the metadata’s type  (as an associated type)+* Extracting metadata from a pointer+* Reconstructing a pointer from a data pointer and metadata+* Representing vtables, the metadata for trait objects, as a type with some limited API++This RFC does *not* propose a mechanism for defining custom dynamically-sized types,+but tries to stay compatible with future proposals that do.+++# Background+[background]: #background++Typical high-level code doesn’t need to worry about fat pointers,+a reference `&Foo` “just works” wether or not `Foo` is a DST.+But unsafe code such as a custom collection library may want to access a fat pointer’s+components separately.++In Rust 1.11 we *removed* a [`std::raw::Repr`] trait and a [`std::raw::Slice`] type+from the standard library.+`Slice` could be `transmute`d to a `&[U]` or `&mut [U]` reference to a slice+as it was guaranteed to have the same memory layout.+This was replaced with more specific and less wildly unsafe+`std::slice::from_raw_parts` and `std::slice::from_raw_parts_mut` functions,+together with `as_ptr` and `len` methods that extract each fat pointer component separatly.++For trait objects, where we still have an unstable `std::raw::TraitObject` type+that can only be used with `transmute`:++```rust+#[repr(C)]+pub struct TraitObject {+    pub data: *mut (),+    pub vtable: *mut (),+}+```++[`std::raw::Repr`]: https://doc.rust-lang.org/1.10.0/std/raw/trait.Repr.html+[`std::raw::Slice`]: https://doc.rust-lang.org/1.10.0/std/raw/struct.Slice.html+[`std::raw::TraitObjet`]: https://doc.rust-lang.org/1.30.0/std/raw/struct.TraitObject.html+++# Motivation+[motivation]: #motivation++We now have APIs in Stable Rust to let unsafe code freely and reliably manipulate slices,+accessing the separate components of a fat pointers and then re-assembling them.+However `std::raw::TraitObject` is still unstable,+but it’s probably not the style of API that we’ll want to stabilize+as it encourages dangerous `transmute` calls.+This is a “hole” in available APIs to manipulate existing Rust types.++For example [this library][lib] stores multiple trait objects of varying size+in contiguous memory together with their vtable pointers,+and during iteration recreates fat pointers from separate data and vtable pointers.++The new `Thin` trait alias also expanding to [extern types] some APIs+that were unnecessarily restricted to `Sized` types+because there was previously no way to express pointer-thinness in generic code.++[lib]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=bbeecccc025f5a7a0ad06086678e13f3+++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation+++Let’s build generic type similar to `Box<dyn Trait>`,+but where the vtable pointer is stored in heap memory next to the value+so that the pointer is thin.+First, let’s get some boilerplate out of the way:++```rust+use std::marker::{PhantomData, Unsize};+use std::ptr::{self, DynMetadata};++trait DynTrait = Pointee<Metadata=DynMetadata>;++pub struct ThinBox<Dyn: ?Sized + DynTrait> {+    ptr: ptr::NonNull<WithMeta<()>>,+    phantom: PhantomData<Dyn>,+}++#[repr(C)]+struct WithMeta<T: ?Sized> {+    vtable: DynMetadata,+    value: T,+}+```++Since [unsized rvalues] are not implemented yet,+our constructor is going to “unsize” from a concrete type that implements our trait.+The `Unsize` bound ensures we can cast from `&S` to a `&Dyn` trait object+and construct the appopriate metadata.++[unsized rvalues]: https://github.com/rust-lang/rust/issues/48055++We let `Box` do the memory layout computation and allocation:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    pub fn new_unsize<S>(value: S) -> Self where S: Unsize<Dyn> {+        let vtable = ptr::metadata(&value as &Dyn);+        let ptr = Box::into_raw_non_null(Box::new(WithMeta { vtable, value })).cast();+        ThinBox { ptr, phantom: PhantomData }+    }+}+```++(Another possible constructor is `pub fn new_copy(value: &Dyn) where Dyn: Copy`,+but it would involve slightly more code.)++Accessing the value requires knowing its alignment:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    fn data_ptr(&self) -> *mut () {+        unsafe {+            let offset = std::mem::size_of::<DynMetadata>();+            let value_align = self.ptr.as_ref().vtable.align();+            let offset = align_up_to(offset, value_align);+            (self.ptr.as_ptr() as *mut u8).add(offset) as *mut ()+        }+    }+}++/// <https://github.com/rust-lang/rust/blob/1.30.0/src/libcore/alloc.rs#L199-L219>+fn align_up_to(offset: usize, align: usize) -> usize {+    offset.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1)+}++// Similarly Deref+impl<Dyn: ?Sized + DynTrait> DerefMut for ThinBox<Dyn> {+    fn deref_mut(&mut self) -> &mut Dyn {+        unsafe {+            &mut *<*mut Dyn>::from_raw_parts(self.data_ptr(), *self.ptr.as_ref().vtable)+        }+    }+}+```++Finally, in `Drop` we can take advantage of `Box` again,+but this time++```rust+impl<Dyn: ?Sized + DynTrait> Drop for ThinBox<Dyn> {+    fn drop(&mut self) {+        unsafe {+            Box::<Dyn>::from_raw(&mut **self);+        }+    }+}+```+++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++The APIs whose full definition is found below+are added to `core::ptr` and re-exported in `std::ptr`:++* A `Pointee` trait,+  implemented automatically for all types+  (similar to how `Sized` and `Unsize` are implemented automatically).+* A `Thin` [trait alias].+  If this RFC is implemented before type aliases are,+  uses of `Thin` should be replaced with its definition.+* A `metadata` free function+* A `DynMetadata` struct+* A `from_raw_parts` constructor for each of `*const T` and `*mut T`++The bounds on `null()` and `null_mut()` function in that same module+as well as the `NonNull::dangling` constructor+are changed from (implicit) `T: Sized` to `T: ?Sized + Thin`.+Similarly for the `U` type parameter of the `NonNull::cast` method.+This enables using those functions with [extern types].++The `Pointee` trait is implemented for all types.+This can be relied on in generic code,+even if a type parameter `T` does not have an explicit `T: Pointee` bound.+This is similar to how the `Any` trait can be used without an explicit `T: Any` bound,+only `T: 'static`, because a blanket `impl<T: 'static> Any for T {…}` exists.+(Except that `Pointee` is not restricted to `'static`.)++For the purpose of pointer casts being allowed by the `as` operator,+a pointer to `T` is considered to be thin if `T: Thin` instead of `T: Sized`.+This similarly includes extern types.++`std::raw::TraitObject` and `std::raw` are deprecated and eventually removed.++[trait alias]: https://github.com/rust-lang/rust/issues/41517+[extern types]: https://github.com/rust-lang/rust/issues/43467++```rust+/// This trait is automatically implement for every type.+///+/// Raw pointer types and reference types in Rust can be thought of as made of two parts:+/// a data pointer that contains the memory address of the value, and some metadata.+///+/// For statically-sized types (that implement the `Sized` traits)+/// as well as for `extern` types,+/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.+///+/// Pointers to [dynamically-sized types][dst] are said to be “fat”+/// and have non-zero-sized metadata:+///+/// * For structs whose last field is a DST, metadata is the metadata for the last field+/// * For the `str` type, metadata is the length in bytes as `usize`+/// * For slice types like `[T]`, metadata is the length in items as `usize`+/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata`].+///+/// In the future, the Rust language may gain new kinds of types+/// that have different pointer metadata.+///+/// Pointer metadata can be extracted from a pointer or reference with the [`metadata`] function.+/// The data pointer can be extracted by casting a (fat) pointer+/// to a (thin) pointer to a `Sized` type the `as` operator,+/// for example `(x: &dyn SomeTrait) as *const SomeTrait as *const ()`.+///+/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts+#[lang = "pointee"]+pub trait Pointee {+    /// The type for metadata in pointers and references to `Self`.+    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin + 'static;+}++/// Pointers to types implementing this trait alias are “thin”:+///+/// ```rust+/// fn this_never_panics<T: std::ptr::Thin>() {+///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())+/// }+/// ```+pub trait Thin = Pointee<Metadata=()>;

This RFCs would enable a third-party library to implement a type like ThinBox that stores the metadata in the heap allocation and keeps the Box-like pointer thin.

SimonSapin

comment created time in a month

PullRequestReviewEvent

push eventSimonSapin/rfcs

Simon Sapin

commit sha 29c754710638cbf6236b8a7c404e2d9fd8c49101

Pointer metadata RFC: use `NonNull` instead of `&'static` for vtable pointers In response to https://github.com/rust-lang/rfcs/pull/2580#discussion_r486505016

view details

Simon Sapin

commit sha 1e5622f01d2912a687f7761afc9f3b0c45745419

Pointer metadata RFC: add unresolved question for parameterizing `DynMetadata`

view details

push time in a month

Pull request review commentrust-lang/rfcs

RFC: Pointer metadata & VTable

+- Feature Name: `ptr-meta`+- Start Date: 2018-10-26+- RFC PR:+- Rust Issue:++# Summary+[summary]: #summary++Add generic APIs that allow manipulating the metadata of fat pointers:++* Naming the metadata’s type  (as an associated type)+* Extracting metadata from a pointer+* Reconstructing a pointer from a data pointer and metadata+* Representing vtables, the metadata for trait objects, as a type with some limited API++This RFC does *not* propose a mechanism for defining custom dynamically-sized types,+but tries to stay compatible with future proposals that do.+++# Background+[background]: #background++Typical high-level code doesn’t need to worry about fat pointers,+a reference `&Foo` “just works” wether or not `Foo` is a DST.+But unsafe code such as a custom collection library may want to access a fat pointer’s+components separately.++In Rust 1.11 we *removed* a [`std::raw::Repr`] trait and a [`std::raw::Slice`] type+from the standard library.+`Slice` could be `transmute`d to a `&[U]` or `&mut [U]` reference to a slice+as it was guaranteed to have the same memory layout.+This was replaced with more specific and less wildly unsafe+`std::slice::from_raw_parts` and `std::slice::from_raw_parts_mut` functions,+together with `as_ptr` and `len` methods that extract each fat pointer component separatly.++For trait objects, where we still have an unstable `std::raw::TraitObject` type+that can only be used with `transmute`:++```rust+#[repr(C)]+pub struct TraitObject {+    pub data: *mut (),+    pub vtable: *mut (),+}+```++[`std::raw::Repr`]: https://doc.rust-lang.org/1.10.0/std/raw/trait.Repr.html+[`std::raw::Slice`]: https://doc.rust-lang.org/1.10.0/std/raw/struct.Slice.html+[`std::raw::TraitObjet`]: https://doc.rust-lang.org/1.30.0/std/raw/struct.TraitObject.html+++# Motivation+[motivation]: #motivation++We now have APIs in Stable Rust to let unsafe code freely and reliably manipulate slices,+accessing the separate components of a fat pointers and then re-assembling them.+However `std::raw::TraitObject` is still unstable,+but it’s probably not the style of API that we’ll want to stabilize+as it encourages dangerous `transmute` calls.+This is a “hole” in available APIs to manipulate existing Rust types.++For example [this library][lib] stores multiple trait objects of varying size+in contiguous memory together with their vtable pointers,+and during iteration recreates fat pointers from separate data and vtable pointers.++The new `Thin` trait alias also expanding to [extern types] some APIs+that were unnecessarily restricted to `Sized` types+because there was previously no way to express pointer-thinness in generic code.++[lib]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=bbeecccc025f5a7a0ad06086678e13f3+++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation+++Let’s build generic type similar to `Box<dyn Trait>`,+but where the vtable pointer is stored in heap memory next to the value+so that the pointer is thin.+First, let’s get some boilerplate out of the way:++```rust+use std::marker::{PhantomData, Unsize};+use std::ptr::{self, DynMetadata};++trait DynTrait = Pointee<Metadata=DynMetadata>;++pub struct ThinBox<Dyn: ?Sized + DynTrait> {+    ptr: ptr::NonNull<WithMeta<()>>,+    phantom: PhantomData<Dyn>,+}++#[repr(C)]+struct WithMeta<T: ?Sized> {+    vtable: DynMetadata,+    value: T,+}+```++Since [unsized rvalues] are not implemented yet,+our constructor is going to “unsize” from a concrete type that implements our trait.+The `Unsize` bound ensures we can cast from `&S` to a `&Dyn` trait object+and construct the appopriate metadata.++[unsized rvalues]: https://github.com/rust-lang/rust/issues/48055++We let `Box` do the memory layout computation and allocation:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    pub fn new_unsize<S>(value: S) -> Self where S: Unsize<Dyn> {+        let vtable = ptr::metadata(&value as &Dyn);+        let ptr = Box::into_raw_non_null(Box::new(WithMeta { vtable, value })).cast();+        ThinBox { ptr, phantom: PhantomData }+    }+}+```++(Another possible constructor is `pub fn new_copy(value: &Dyn) where Dyn: Copy`,+but it would involve slightly more code.)++Accessing the value requires knowing its alignment:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    fn data_ptr(&self) -> *mut () {+        unsafe {+            let offset = std::mem::size_of::<DynMetadata>();+            let value_align = self.ptr.as_ref().vtable.align();+            let offset = align_up_to(offset, value_align);+            (self.ptr.as_ptr() as *mut u8).add(offset) as *mut ()+        }+    }+}++/// <https://github.com/rust-lang/rust/blob/1.30.0/src/libcore/alloc.rs#L199-L219>+fn align_up_to(offset: usize, align: usize) -> usize {+    offset.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1)+}++// Similarly Deref+impl<Dyn: ?Sized + DynTrait> DerefMut for ThinBox<Dyn> {+    fn deref_mut(&mut self) -> &mut Dyn {+        unsafe {+            &mut *<*mut Dyn>::from_raw_parts(self.data_ptr(), *self.ptr.as_ref().vtable)+        }+    }+}+```++Finally, in `Drop` we can take advantage of `Box` again,+but this time++```rust+impl<Dyn: ?Sized + DynTrait> Drop for ThinBox<Dyn> {+    fn drop(&mut self) {+        unsafe {+            Box::<Dyn>::from_raw(&mut **self);+        }+    }+}+```+++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++The APIs whose full definition is found below+are added to `core::ptr` and re-exported in `std::ptr`:++* A `Pointee` trait,+  implemented automatically for all types+  (similar to how `Sized` and `Unsize` are implemented automatically).+* A `Thin` [trait alias].+  If this RFC is implemented before type aliases are,+  uses of `Thin` should be replaced with its definition.+* A `metadata` free function+* A `DynMetadata` struct+* A `from_raw_parts` constructor for each of `*const T` and `*mut T`++The bounds on `null()` and `null_mut()` function in that same module+as well as the `NonNull::dangling` constructor+are changed from (implicit) `T: Sized` to `T: ?Sized + Thin`.+Similarly for the `U` type parameter of the `NonNull::cast` method.+This enables using those functions with [extern types].++The `Pointee` trait is implemented for all types.+This can be relied on in generic code,+even if a type parameter `T` does not have an explicit `T: Pointee` bound.+This is similar to how the `Any` trait can be used without an explicit `T: Any` bound,+only `T: 'static`, because a blanket `impl<T: 'static> Any for T {…}` exists.+(Except that `Pointee` is not restricted to `'static`.)++For the purpose of pointer casts being allowed by the `as` operator,+a pointer to `T` is considered to be thin if `T: Thin` instead of `T: Sized`.+This similarly includes extern types.++`std::raw::TraitObject` and `std::raw` are deprecated and eventually removed.++[trait alias]: https://github.com/rust-lang/rust/issues/41517+[extern types]: https://github.com/rust-lang/rust/issues/43467++```rust+/// This trait is automatically implement for every type.+///+/// Raw pointer types and reference types in Rust can be thought of as made of two parts:+/// a data pointer that contains the memory address of the value, and some metadata.+///+/// For statically-sized types (that implement the `Sized` traits)+/// as well as for `extern` types,+/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.+///+/// Pointers to [dynamically-sized types][dst] are said to be “fat”+/// and have non-zero-sized metadata:+///+/// * For structs whose last field is a DST, metadata is the metadata for the last field+/// * For the `str` type, metadata is the length in bytes as `usize`+/// * For slice types like `[T]`, metadata is the length in items as `usize`+/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata`].+///+/// In the future, the Rust language may gain new kinds of types+/// that have different pointer metadata.+///+/// Pointer metadata can be extracted from a pointer or reference with the [`metadata`] function.+/// The data pointer can be extracted by casting a (fat) pointer+/// to a (thin) pointer to a `Sized` type the `as` operator,+/// for example `(x: &dyn SomeTrait) as *const SomeTrait as *const ()`.+///+/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts+#[lang = "pointee"]+pub trait Pointee {+    /// The type for metadata in pointers and references to `Self`.+    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin + 'static;+}++/// Pointers to types implementing this trait alias are “thin”:+///+/// ```rust+/// fn this_never_panics<T: std::ptr::Thin>() {+///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())+/// }+/// ```+pub trait Thin = Pointee<Metadata=()>;

I believe it's better to actually introduce thin pointers instead of using this trait alias.

I don’t understand what "actually introduce" means.

The Thin trait alias proposed here describes an existing property of some existing types and the existing pointer/reference types to those. *const u32 is a thin pointer, *const str is not. Therefore u32: Thin holds, str: Thin does not.

The problem is that this trait alias doesn't necessary play well with structs containing DSTs (which might again be "composed" DSTs). It should be possible to have a thin pointer to such a struct

In today’s Rust a struct that contains a DST field is itself also a DST and therefore pointers to it are wide, not thin.

Introducing thin pointers to DSTs (structs or not) is an entirely new language feature that is not part of this RFC. If you feel that feature should be pursued, consider writing a separate RFC for it.

SimonSapin

comment created time in a month

PullRequestReviewEvent

Pull request review commentrust-lang/rfcs

RFC: Pointer metadata & VTable

+- Feature Name: `ptr-meta`+- Start Date: 2018-10-26+- RFC PR:+- Rust Issue:++# Summary+[summary]: #summary++Add generic APIs that allow manipulating the metadata of fat pointers:++* Naming the metadata’s type  (as an associated type)+* Extracting metadata from a pointer+* Reconstructing a pointer from a data pointer and metadata+* Representing vtables, the metadata for trait objects, as a type with some limited API++This RFC does *not* propose a mechanism for defining custom dynamically-sized types,+but tries to stay compatible with future proposals that do.+++# Background+[background]: #background++Typical high-level code doesn’t need to worry about fat pointers,+a reference `&Foo` “just works” wether or not `Foo` is a DST.+But unsafe code such as a custom collection library may want to access a fat pointer’s+components separately.++In Rust 1.11 we *removed* a [`std::raw::Repr`] trait and a [`std::raw::Slice`] type+from the standard library.+`Slice` could be `transmute`d to a `&[U]` or `&mut [U]` reference to a slice+as it was guaranteed to have the same memory layout.+This was replaced with more specific and less wildly unsafe+`std::slice::from_raw_parts` and `std::slice::from_raw_parts_mut` functions,+together with `as_ptr` and `len` methods that extract each fat pointer component separatly.++For trait objects, where we still have an unstable `std::raw::TraitObject` type+that can only be used with `transmute`:++```rust+#[repr(C)]+pub struct TraitObject {+    pub data: *mut (),+    pub vtable: *mut (),+}+```++[`std::raw::Repr`]: https://doc.rust-lang.org/1.10.0/std/raw/trait.Repr.html+[`std::raw::Slice`]: https://doc.rust-lang.org/1.10.0/std/raw/struct.Slice.html+[`std::raw::TraitObjet`]: https://doc.rust-lang.org/1.30.0/std/raw/struct.TraitObject.html+++# Motivation+[motivation]: #motivation++We now have APIs in Stable Rust to let unsafe code freely and reliably manipulate slices,+accessing the separate components of a fat pointers and then re-assembling them.+However `std::raw::TraitObject` is still unstable,+but it’s probably not the style of API that we’ll want to stabilize+as it encourages dangerous `transmute` calls.+This is a “hole” in available APIs to manipulate existing Rust types.++For example [this library][lib] stores multiple trait objects of varying size+in contiguous memory together with their vtable pointers,+and during iteration recreates fat pointers from separate data and vtable pointers.++The new `Thin` trait alias also expanding to [extern types] some APIs+that were unnecessarily restricted to `Sized` types+because there was previously no way to express pointer-thinness in generic code.++[lib]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=bbeecccc025f5a7a0ad06086678e13f3+++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation+++Let’s build generic type similar to `Box<dyn Trait>`,+but where the vtable pointer is stored in heap memory next to the value+so that the pointer is thin.+First, let’s get some boilerplate out of the way:++```rust+use std::marker::{PhantomData, Unsize};+use std::ptr::{self, DynMetadata};++trait DynTrait = Pointee<Metadata=DynMetadata>;++pub struct ThinBox<Dyn: ?Sized + DynTrait> {+    ptr: ptr::NonNull<WithMeta<()>>,+    phantom: PhantomData<Dyn>,+}++#[repr(C)]+struct WithMeta<T: ?Sized> {+    vtable: DynMetadata,+    value: T,+}+```++Since [unsized rvalues] are not implemented yet,+our constructor is going to “unsize” from a concrete type that implements our trait.+The `Unsize` bound ensures we can cast from `&S` to a `&Dyn` trait object+and construct the appopriate metadata.++[unsized rvalues]: https://github.com/rust-lang/rust/issues/48055++We let `Box` do the memory layout computation and allocation:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    pub fn new_unsize<S>(value: S) -> Self where S: Unsize<Dyn> {+        let vtable = ptr::metadata(&value as &Dyn);+        let ptr = Box::into_raw_non_null(Box::new(WithMeta { vtable, value })).cast();+        ThinBox { ptr, phantom: PhantomData }+    }+}+```++(Another possible constructor is `pub fn new_copy(value: &Dyn) where Dyn: Copy`,+but it would involve slightly more code.)++Accessing the value requires knowing its alignment:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    fn data_ptr(&self) -> *mut () {+        unsafe {+            let offset = std::mem::size_of::<DynMetadata>();+            let value_align = self.ptr.as_ref().vtable.align();+            let offset = align_up_to(offset, value_align);+            (self.ptr.as_ptr() as *mut u8).add(offset) as *mut ()+        }+    }+}++/// <https://github.com/rust-lang/rust/blob/1.30.0/src/libcore/alloc.rs#L199-L219>+fn align_up_to(offset: usize, align: usize) -> usize {+    offset.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1)+}++// Similarly Deref+impl<Dyn: ?Sized + DynTrait> DerefMut for ThinBox<Dyn> {+    fn deref_mut(&mut self) -> &mut Dyn {+        unsafe {+            &mut *<*mut Dyn>::from_raw_parts(self.data_ptr(), *self.ptr.as_ref().vtable)+        }+    }+}+```++Finally, in `Drop` we can take advantage of `Box` again,+but this time++```rust+impl<Dyn: ?Sized + DynTrait> Drop for ThinBox<Dyn> {+    fn drop(&mut self) {+        unsafe {+            Box::<Dyn>::from_raw(&mut **self);+        }+    }+}+```+++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++The APIs whose full definition is found below+are added to `core::ptr` and re-exported in `std::ptr`:++* A `Pointee` trait,+  implemented automatically for all types+  (similar to how `Sized` and `Unsize` are implemented automatically).+* A `Thin` [trait alias].+  If this RFC is implemented before type aliases are,+  uses of `Thin` should be replaced with its definition.+* A `metadata` free function+* A `DynMetadata` struct+* A `from_raw_parts` constructor for each of `*const T` and `*mut T`++The bounds on `null()` and `null_mut()` function in that same module+as well as the `NonNull::dangling` constructor+are changed from (implicit) `T: Sized` to `T: ?Sized + Thin`.+Similarly for the `U` type parameter of the `NonNull::cast` method.+This enables using those functions with [extern types].++The `Pointee` trait is implemented for all types.+This can be relied on in generic code,+even if a type parameter `T` does not have an explicit `T: Pointee` bound.+This is similar to how the `Any` trait can be used without an explicit `T: Any` bound,+only `T: 'static`, because a blanket `impl<T: 'static> Any for T {…}` exists.+(Except that `Pointee` is not restricted to `'static`.)++For the purpose of pointer casts being allowed by the `as` operator,+a pointer to `T` is considered to be thin if `T: Thin` instead of `T: Sized`.+This similarly includes extern types.++`std::raw::TraitObject` and `std::raw` are deprecated and eventually removed.++[trait alias]: https://github.com/rust-lang/rust/issues/41517+[extern types]: https://github.com/rust-lang/rust/issues/43467++```rust+/// This trait is automatically implement for every type.+///+/// Raw pointer types and reference types in Rust can be thought of as made of two parts:+/// a data pointer that contains the memory address of the value, and some metadata.+///+/// For statically-sized types (that implement the `Sized` traits)+/// as well as for `extern` types,+/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.+///+/// Pointers to [dynamically-sized types][dst] are said to be “fat”+/// and have non-zero-sized metadata:+///+/// * For structs whose last field is a DST, metadata is the metadata for the last field+/// * For the `str` type, metadata is the length in bytes as `usize`+/// * For slice types like `[T]`, metadata is the length in items as `usize`+/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata`].+///+/// In the future, the Rust language may gain new kinds of types+/// that have different pointer metadata.+///+/// Pointer metadata can be extracted from a pointer or reference with the [`metadata`] function.+/// The data pointer can be extracted by casting a (fat) pointer+/// to a (thin) pointer to a `Sized` type the `as` operator,+/// for example `(x: &dyn SomeTrait) as *const SomeTrait as *const ()`.+///+/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts+#[lang = "pointee"]+pub trait Pointee {+    /// The type for metadata in pointers and references to `Self`.+    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin + 'static;+}++/// Pointers to types implementing this trait alias are “thin”:+///+/// ```rust+/// fn this_never_panics<T: std::ptr::Thin>() {+///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())+/// }+/// ```+pub trait Thin = Pointee<Metadata=()>;++/// Extract the metadata component of a pointer.+///+/// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function+/// as they implicitly coerce to `*const T`.+/// For example:+///+/// ```+/// assert_eq(std::ptr::metadata("foo"), 3_usize);+/// ```+///+/// Note that the data component of a (fat) pointer can be extracted by casting+/// to a (thin) pointer to any `Sized` type:+///+/// ```+/// # trait SomeTrait {}+/// # fn example(something: &SomeTrait) {+/// let object: &SomeTrait = something;+/// let data_ptr = object as *const SomeTrait as *const ();+/// # }+/// ```+pub fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {…}++impl<T: ?Sized> *const T {+    pub fn from_raw_parts(data: *const (), meta: <T as Pointee>::Metadata) -> Self {…}+}++impl<T: ?Sized> *mut T {+    pub fn from_raw_parts(data: *mut (), meta: <T as Pointee>::Metadata) -> Self {…}+}++impl<T: ?Sized> NonNull<T> {+    pub fn from_raw_parts(data: NonNull<()>, meta: <T as Pointee>::Metadata) -> Self {+        unsafe {+            NonNull::new_unchecked(<*mut _>::from_raw_parts(data.as_ptr(), meta))+        }+    }+}++/// The metadata for a `dyn SomeTrait` trait object type.+///+/// It is a pointer to a vtable (virtual call table)+/// that represents all the necessary information+/// to manipulate the concrete type stored inside a trait object.+/// The vtable notably it contains:+///+/// * type size+/// * type alignment+/// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data)+/// * pointers to all the methods for the type’s implementation of the trait+///+/// Note that the first three are special because they’re necessary to allocate, drop,+/// and deallocate any trait object.+///+/// The layout of vtables is still unspecified, so this type is a more-type-safe+/// convenience for accessing those 3 special values. Note however that `DynMetadata` does+/// not actually know the trait it’s associated with, indicating that, at very least,+/// the location of `size`, `align`, and `drop_in_place` is identical for all+/// trait object vtables in a single program.+#[derive(Copy, Clone)]+pub struct DynMetadata {

I’ve added an unresolved question.

SimonSapin

comment created time in a month

PullRequestReviewEvent

Pull request review commentrust-lang/rfcs

RFC: Pointer metadata & VTable

+- Feature Name: `ptr-meta`+- Start Date: 2018-10-26+- RFC PR:+- Rust Issue:++# Summary+[summary]: #summary++Add generic APIs that allow manipulating the metadata of fat pointers:++* Naming the metadata’s type  (as an associated type)+* Extracting metadata from a pointer+* Reconstructing a pointer from a data pointer and metadata+* Representing vtables, the metadata for trait objects, as a type with some limited API++This RFC does *not* propose a mechanism for defining custom dynamically-sized types,+but tries to stay compatible with future proposals that do.+++# Background+[background]: #background++Typical high-level code doesn’t need to worry about fat pointers,+a reference `&Foo` “just works” wether or not `Foo` is a DST.+But unsafe code such as a custom collection library may want to access a fat pointer’s+components separately.++In Rust 1.11 we *removed* a [`std::raw::Repr`] trait and a [`std::raw::Slice`] type+from the standard library.+`Slice` could be `transmute`d to a `&[U]` or `&mut [U]` reference to a slice+as it was guaranteed to have the same memory layout.+This was replaced with more specific and less wildly unsafe+`std::slice::from_raw_parts` and `std::slice::from_raw_parts_mut` functions,+together with `as_ptr` and `len` methods that extract each fat pointer component separatly.++For trait objects, where we still have an unstable `std::raw::TraitObject` type+that can only be used with `transmute`:++```rust+#[repr(C)]+pub struct TraitObject {+    pub data: *mut (),+    pub vtable: *mut (),+}+```++[`std::raw::Repr`]: https://doc.rust-lang.org/1.10.0/std/raw/trait.Repr.html+[`std::raw::Slice`]: https://doc.rust-lang.org/1.10.0/std/raw/struct.Slice.html+[`std::raw::TraitObjet`]: https://doc.rust-lang.org/1.30.0/std/raw/struct.TraitObject.html+++# Motivation+[motivation]: #motivation++We now have APIs in Stable Rust to let unsafe code freely and reliably manipulate slices,+accessing the separate components of a fat pointers and then re-assembling them.+However `std::raw::TraitObject` is still unstable,+but it’s probably not the style of API that we’ll want to stabilize+as it encourages dangerous `transmute` calls.+This is a “hole” in available APIs to manipulate existing Rust types.++For example [this library][lib] stores multiple trait objects of varying size+in contiguous memory together with their vtable pointers,+and during iteration recreates fat pointers from separate data and vtable pointers.++The new `Thin` trait alias also expanding to [extern types] some APIs+that were unnecessarily restricted to `Sized` types+because there was previously no way to express pointer-thinness in generic code.++[lib]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=bbeecccc025f5a7a0ad06086678e13f3+++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation+++Let’s build generic type similar to `Box<dyn Trait>`,+but where the vtable pointer is stored in heap memory next to the value+so that the pointer is thin.+First, let’s get some boilerplate out of the way:++```rust+use std::marker::{PhantomData, Unsize};+use std::ptr::{self, DynMetadata};++trait DynTrait = Pointee<Metadata=DynMetadata>;++pub struct ThinBox<Dyn: ?Sized + DynTrait> {+    ptr: ptr::NonNull<WithMeta<()>>,+    phantom: PhantomData<Dyn>,+}++#[repr(C)]+struct WithMeta<T: ?Sized> {+    vtable: DynMetadata,+    value: T,+}+```++Since [unsized rvalues] are not implemented yet,+our constructor is going to “unsize” from a concrete type that implements our trait.+The `Unsize` bound ensures we can cast from `&S` to a `&Dyn` trait object+and construct the appopriate metadata.++[unsized rvalues]: https://github.com/rust-lang/rust/issues/48055++We let `Box` do the memory layout computation and allocation:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    pub fn new_unsize<S>(value: S) -> Self where S: Unsize<Dyn> {+        let vtable = ptr::metadata(&value as &Dyn);+        let ptr = Box::into_raw_non_null(Box::new(WithMeta { vtable, value })).cast();+        ThinBox { ptr, phantom: PhantomData }+    }+}+```++(Another possible constructor is `pub fn new_copy(value: &Dyn) where Dyn: Copy`,+but it would involve slightly more code.)++Accessing the value requires knowing its alignment:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    fn data_ptr(&self) -> *mut () {+        unsafe {+            let offset = std::mem::size_of::<DynMetadata>();+            let value_align = self.ptr.as_ref().vtable.align();+            let offset = align_up_to(offset, value_align);+            (self.ptr.as_ptr() as *mut u8).add(offset) as *mut ()+        }+    }+}++/// <https://github.com/rust-lang/rust/blob/1.30.0/src/libcore/alloc.rs#L199-L219>+fn align_up_to(offset: usize, align: usize) -> usize {+    offset.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1)+}++// Similarly Deref+impl<Dyn: ?Sized + DynTrait> DerefMut for ThinBox<Dyn> {+    fn deref_mut(&mut self) -> &mut Dyn {+        unsafe {+            &mut *<*mut Dyn>::from_raw_parts(self.data_ptr(), *self.ptr.as_ref().vtable)+        }+    }+}+```++Finally, in `Drop` we can take advantage of `Box` again,+but this time++```rust+impl<Dyn: ?Sized + DynTrait> Drop for ThinBox<Dyn> {+    fn drop(&mut self) {+        unsafe {+            Box::<Dyn>::from_raw(&mut **self);+        }+    }+}+```+++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++The APIs whose full definition is found below+are added to `core::ptr` and re-exported in `std::ptr`:++* A `Pointee` trait,+  implemented automatically for all types+  (similar to how `Sized` and `Unsize` are implemented automatically).+* A `Thin` [trait alias].+  If this RFC is implemented before type aliases are,+  uses of `Thin` should be replaced with its definition.+* A `metadata` free function+* A `DynMetadata` struct+* A `from_raw_parts` constructor for each of `*const T` and `*mut T`++The bounds on `null()` and `null_mut()` function in that same module+as well as the `NonNull::dangling` constructor+are changed from (implicit) `T: Sized` to `T: ?Sized + Thin`.+Similarly for the `U` type parameter of the `NonNull::cast` method.+This enables using those functions with [extern types].++The `Pointee` trait is implemented for all types.+This can be relied on in generic code,+even if a type parameter `T` does not have an explicit `T: Pointee` bound.+This is similar to how the `Any` trait can be used without an explicit `T: Any` bound,+only `T: 'static`, because a blanket `impl<T: 'static> Any for T {…}` exists.+(Except that `Pointee` is not restricted to `'static`.)++For the purpose of pointer casts being allowed by the `as` operator,+a pointer to `T` is considered to be thin if `T: Thin` instead of `T: Sized`.+This similarly includes extern types.++`std::raw::TraitObject` and `std::raw` are deprecated and eventually removed.++[trait alias]: https://github.com/rust-lang/rust/issues/41517+[extern types]: https://github.com/rust-lang/rust/issues/43467++```rust+/// This trait is automatically implement for every type.+///+/// Raw pointer types and reference types in Rust can be thought of as made of two parts:+/// a data pointer that contains the memory address of the value, and some metadata.+///+/// For statically-sized types (that implement the `Sized` traits)+/// as well as for `extern` types,+/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.+///+/// Pointers to [dynamically-sized types][dst] are said to be “fat”+/// and have non-zero-sized metadata:+///+/// * For structs whose last field is a DST, metadata is the metadata for the last field+/// * For the `str` type, metadata is the length in bytes as `usize`+/// * For slice types like `[T]`, metadata is the length in items as `usize`+/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata`].+///+/// In the future, the Rust language may gain new kinds of types+/// that have different pointer metadata.+///+/// Pointer metadata can be extracted from a pointer or reference with the [`metadata`] function.+/// The data pointer can be extracted by casting a (fat) pointer+/// to a (thin) pointer to a `Sized` type the `as` operator,+/// for example `(x: &dyn SomeTrait) as *const SomeTrait as *const ()`.+///+/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts+#[lang = "pointee"]+pub trait Pointee {+    /// The type for metadata in pointers and references to `Self`.+    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin + 'static;+}++/// Pointers to types implementing this trait alias are “thin”:+///+/// ```rust+/// fn this_never_panics<T: std::ptr::Thin>() {+///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())+/// }+/// ```+pub trait Thin = Pointee<Metadata=()>;++/// Extract the metadata component of a pointer.+///+/// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function+/// as they implicitly coerce to `*const T`.+/// For example:+///+/// ```+/// assert_eq(std::ptr::metadata("foo"), 3_usize);+/// ```+///+/// Note that the data component of a (fat) pointer can be extracted by casting+/// to a (thin) pointer to any `Sized` type:+///+/// ```+/// # trait SomeTrait {}+/// # fn example(something: &SomeTrait) {+/// let object: &SomeTrait = something;+/// let data_ptr = object as *const SomeTrait as *const ();+/// # }+/// ```+pub fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {…}++impl<T: ?Sized> *const T {+    pub fn from_raw_parts(data: *const (), meta: <T as Pointee>::Metadata) -> Self {…}+}++impl<T: ?Sized> *mut T {+    pub fn from_raw_parts(data: *mut (), meta: <T as Pointee>::Metadata) -> Self {…}+}++impl<T: ?Sized> NonNull<T> {+    pub fn from_raw_parts(data: NonNull<()>, meta: <T as Pointee>::Metadata) -> Self {+        unsafe {+            NonNull::new_unchecked(<*mut _>::from_raw_parts(data.as_ptr(), meta))+        }+    }+}++/// The metadata for a `dyn SomeTrait` trait object type.+///+/// It is a pointer to a vtable (virtual call table)+/// that represents all the necessary information+/// to manipulate the concrete type stored inside a trait object.+/// The vtable notably it contains:+///+/// * type size+/// * type alignment+/// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data)+/// * pointers to all the methods for the type’s implementation of the trait+///+/// Note that the first three are special because they’re necessary to allocate, drop,+/// and deallocate any trait object.+///+/// The layout of vtables is still unspecified, so this type is a more-type-safe+/// convenience for accessing those 3 special values. Note however that `DynMetadata` does+/// not actually know the trait it’s associated with, indicating that, at very least,+/// the location of `size`, `align`, and `drop_in_place` is identical for all+/// trait object vtables in a single program.+#[derive(Copy, Clone)]+pub struct DynMetadata {+    vtable_ptr: &'static (),

This is private field, so its exact type is an implementation detail that’s not too important for the purpose of this RFC. I’ve changed it to NonNull.

(I’m not sure whether making all &ZeroSizeType have a fixed address is realistic or what advantage that would bring, but that’s out of scope for this RFC.)

SimonSapin

comment created time in a month

PullRequestReviewEvent

Pull request review commentrust-lang/rfcs

RFC: Pointer metadata & VTable

+- Feature Name: `ptr-meta`+- Start Date: 2018-10-26+- RFC PR:+- Rust Issue:++# Summary+[summary]: #summary++Add generic APIs that allow manipulating the metadata of fat pointers:++* Naming the metadata’s type  (as an associated type)+* Extracting metadata from a pointer+* Reconstructing a pointer from a data pointer and metadata+* Representing vtables, the metadata for trait objects, as a type with some limited API++This RFC does *not* propose a mechanism for defining custom dynamically-sized types,+but tries to stay compatible with future proposals that do.+++# Background+[background]: #background++Typical high-level code doesn’t need to worry about fat pointers,+a reference `&Foo` “just works” wether or not `Foo` is a DST.+But unsafe code such as a custom collection library may want to access a fat pointer’s+components separately.++In Rust 1.11 we *removed* a [`std::raw::Repr`] trait and a [`std::raw::Slice`] type+from the standard library.+`Slice` could be `transmute`d to a `&[U]` or `&mut [U]` reference to a slice+as it was guaranteed to have the same memory layout.+This was replaced with more specific and less wildly unsafe+`std::slice::from_raw_parts` and `std::slice::from_raw_parts_mut` functions,+together with `as_ptr` and `len` methods that extract each fat pointer component separatly.++For trait objects, where we still have an unstable `std::raw::TraitObject` type+that can only be used with `transmute`:++```rust+#[repr(C)]+pub struct TraitObject {+    pub data: *mut (),+    pub vtable: *mut (),+}+```++[`std::raw::Repr`]: https://doc.rust-lang.org/1.10.0/std/raw/trait.Repr.html+[`std::raw::Slice`]: https://doc.rust-lang.org/1.10.0/std/raw/struct.Slice.html+[`std::raw::TraitObjet`]: https://doc.rust-lang.org/1.30.0/std/raw/struct.TraitObject.html+++# Motivation+[motivation]: #motivation++We now have APIs in Stable Rust to let unsafe code freely and reliably manipulate slices,+accessing the separate components of a fat pointers and then re-assembling them.+However `std::raw::TraitObject` is still unstable,+but it’s probably not the style of API that we’ll want to stabilize+as it encourages dangerous `transmute` calls.+This is a “hole” in available APIs to manipulate existing Rust types.++For example [this library][lib] stores multiple trait objects of varying size+in contiguous memory together with their vtable pointers,+and during iteration recreates fat pointers from separate data and vtable pointers.++The new `Thin` trait alias also expanding to [extern types] some APIs+that were unnecessarily restricted to `Sized` types+because there was previously no way to express pointer-thinness in generic code.++[lib]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=bbeecccc025f5a7a0ad06086678e13f3+++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation+++Let’s build generic type similar to `Box<dyn Trait>`,+but where the vtable pointer is stored in heap memory next to the value+so that the pointer is thin.+First, let’s get some boilerplate out of the way:++```rust+use std::marker::{PhantomData, Unsize};+use std::ptr::{self, DynMetadata};++trait DynTrait = Pointee<Metadata=DynMetadata>;++pub struct ThinBox<Dyn: ?Sized + DynTrait> {+    ptr: ptr::NonNull<WithMeta<()>>,+    phantom: PhantomData<Dyn>,+}++#[repr(C)]+struct WithMeta<T: ?Sized> {+    vtable: DynMetadata,+    value: T,+}+```++Since [unsized rvalues] are not implemented yet,+our constructor is going to “unsize” from a concrete type that implements our trait.+The `Unsize` bound ensures we can cast from `&S` to a `&Dyn` trait object+and construct the appopriate metadata.++[unsized rvalues]: https://github.com/rust-lang/rust/issues/48055++We let `Box` do the memory layout computation and allocation:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    pub fn new_unsize<S>(value: S) -> Self where S: Unsize<Dyn> {+        let vtable = ptr::metadata(&value as &Dyn);+        let ptr = Box::into_raw_non_null(Box::new(WithMeta { vtable, value })).cast();+        ThinBox { ptr, phantom: PhantomData }+    }+}+```++(Another possible constructor is `pub fn new_copy(value: &Dyn) where Dyn: Copy`,+but it would involve slightly more code.)++Accessing the value requires knowing its alignment:++```rust+impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {+    fn data_ptr(&self) -> *mut () {+        unsafe {+            let offset = std::mem::size_of::<DynMetadata>();+            let value_align = self.ptr.as_ref().vtable.align();+            let offset = align_up_to(offset, value_align);+            (self.ptr.as_ptr() as *mut u8).add(offset) as *mut ()+        }+    }+}++/// <https://github.com/rust-lang/rust/blob/1.30.0/src/libcore/alloc.rs#L199-L219>+fn align_up_to(offset: usize, align: usize) -> usize {+    offset.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1)+}++// Similarly Deref+impl<Dyn: ?Sized + DynTrait> DerefMut for ThinBox<Dyn> {+    fn deref_mut(&mut self) -> &mut Dyn {+        unsafe {+            &mut *<*mut Dyn>::from_raw_parts(self.data_ptr(), *self.ptr.as_ref().vtable)+        }+    }+}+```++Finally, in `Drop` we can take advantage of `Box` again,+but this time++```rust+impl<Dyn: ?Sized + DynTrait> Drop for ThinBox<Dyn> {+    fn drop(&mut self) {+        unsafe {+            Box::<Dyn>::from_raw(&mut **self);+        }+    }+}+```+++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++The APIs whose full definition is found below+are added to `core::ptr` and re-exported in `std::ptr`:++* A `Pointee` trait,+  implemented automatically for all types+  (similar to how `Sized` and `Unsize` are implemented automatically).+* A `Thin` [trait alias].+  If this RFC is implemented before type aliases are,+  uses of `Thin` should be replaced with its definition.+* A `metadata` free function+* A `DynMetadata` struct+* A `from_raw_parts` constructor for each of `*const T` and `*mut T`++The bounds on `null()` and `null_mut()` function in that same module+as well as the `NonNull::dangling` constructor+are changed from (implicit) `T: Sized` to `T: ?Sized + Thin`.+Similarly for the `U` type parameter of the `NonNull::cast` method.+This enables using those functions with [extern types].++The `Pointee` trait is implemented for all types.+This can be relied on in generic code,+even if a type parameter `T` does not have an explicit `T: Pointee` bound.+This is similar to how the `Any` trait can be used without an explicit `T: Any` bound,+only `T: 'static`, because a blanket `impl<T: 'static> Any for T {…}` exists.+(Except that `Pointee` is not restricted to `'static`.)++For the purpose of pointer casts being allowed by the `as` operator,+a pointer to `T` is considered to be thin if `T: Thin` instead of `T: Sized`.+This similarly includes extern types.++`std::raw::TraitObject` and `std::raw` are deprecated and eventually removed.++[trait alias]: https://github.com/rust-lang/rust/issues/41517+[extern types]: https://github.com/rust-lang/rust/issues/43467++```rust+/// This trait is automatically implement for every type.+///+/// Raw pointer types and reference types in Rust can be thought of as made of two parts:+/// a data pointer that contains the memory address of the value, and some metadata.+///+/// For statically-sized types (that implement the `Sized` traits)+/// as well as for `extern` types,+/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.+///+/// Pointers to [dynamically-sized types][dst] are said to be “fat”+/// and have non-zero-sized metadata:+///+/// * For structs whose last field is a DST, metadata is the metadata for the last field+/// * For the `str` type, metadata is the length in bytes as `usize`+/// * For slice types like `[T]`, metadata is the length in items as `usize`+/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata`].+///+/// In the future, the Rust language may gain new kinds of types+/// that have different pointer metadata.+///+/// Pointer metadata can be extracted from a pointer or reference with the [`metadata`] function.+/// The data pointer can be extracted by casting a (fat) pointer+/// to a (thin) pointer to a `Sized` type the `as` operator,+/// for example `(x: &dyn SomeTrait) as *const SomeTrait as *const ()`.+///+/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts+#[lang = "pointee"]+pub trait Pointee {+    /// The type for metadata in pointers and references to `Self`.+    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin + 'static;

Today we have impl<T: ?Sized> !Send for *mut T {} (similarly Sync) in libcore, without a T: Send bound. For a wide pointer to be Send, the metadata needs to be Send as well.

SimonSapin

comment created time in a month

PullRequestReviewEvent

issue commentrust-lang/lang-team

Discuss RFC 2580 (Pointer metadata and vtable)

Thanks @nikomatsakis for getting this moving again. Yes I’d like to attend. I’m in UTC+2. I’m not sure who else should, maybe a few folks who commented the most on the RFC?

@rustonaut I think technical discussion about the proposal should likely stay within the RFC PR comment thread as long as that’s open. Do you mind reposting there?

nikomatsakis

comment created time in a month

issue commentrust-lang/wg-allocators

Should a global allocator always be required, even if it isn't used?

Defaulting to all allocations panicking seems like too much of a footgun to me. However it is possible to opt into this behavior today by defining a #[global_allocator] as Amanieu mentioned. If this choice is common enough it could even be a crate on crates.io

lachlansneff

comment created time in a month

delete branch SimonSapin/team

delete branch : patch-2

delete time in 2 months

PR opened rust-lang/team

Exclude myself (SimonSapin) from rfcbot for T-libs

I’ve been less involved lately, no need to block FCP reviews on me.

CC @rust-lang/libs

+1 -0

0 comment

1 changed file

pr created time in 2 months

push eventSimonSapin/team

Simon Sapin

commit sha c1da926965d550876043974dff9512276319303f

Exclude myself (SimonSapin) from rfcbot for T-libs I’ve been less involved lately, no need to block FCP reviews on me. CC @rust-lang/libs

view details

push time in 2 months

pull request commentservo/servo

Upgrade to rustc 1.48.0-nightly (d006f5734 2020-08-28)

@bors-servo r+

SimonSapin

comment created time in 2 months

PR opened servo/servo

Upgrade to rustc 1.48.0-nightly (d006f5734 2020-08-28)

https://github.com/rust-lang/hashbrown/pull/159 reduced size_of::<HashMap>()

+9 -9

0 comment

2 changed files

pr created time in 2 months

create barnchservo/servo

branch : rustup

created branch time in 2 months

pull request commentservo/rust-url

url: add TryFrom<&[u8]> for Url and TryFrom tests

I feel this should not be implemented. URL parsing is defined over Unicode input. &[u8] and &str are not interchangeable representations of "the same thing", Unicode and bytes are separate "domains" of data and the choice of strict UTF-8 decoding for converting between them should be explicit to users.

(Unfortunately the Matrix link doesn’t seem to work from here.)

acfoltzer

comment created time in 2 months

MemberEvent

push eventSimonSapin/servo

Simon Sapin

commit sha ec548e849ca328ccc18404313369dbffcf0a17b9

Flex items in the box tree

view details

Simon Sapin

commit sha 67d8aa84d2e63503a9d5c250f0eb1eb659f84619

Anonymous flex item for text directly in a flex container

view details

Simon Sapin

commit sha 29005e1626a11cf1fc840998327896297e82d2cc

Keep flex items in `order`-modified document order in the box tree

view details

Simon Sapin

commit sha fff5cd51427c62e0696aa44a1a53e8f5152c8610

Owned `ServoArc<ComputedValues>` in `TraversalHandler`

view details

Simon Sapin

commit sha b9069d48d98bde70d762de86443b25d6c6f72415

Parallelize flex item boxes construction

view details

bors-servo

commit sha 3d6fed85ffffcc289a6e0decb0dd70a2985542b0

Auto merge of #26755 - servo:flexbox, r=nox Add Layout 2020 box tree support for Flexbox, behind a pref CC https://github.com/servo/servo/issues/26639 Layout support will come in future PRs. This one generates a zero-size fragment with no content.

view details

Simon Sapin

commit sha 36920abfe86e6a3a2d8c989a3ba1f21a5cee54e5

Use `const` instead of `static mut` in script/dom/eventtarget.rs There is no mutability there.

view details

bors-servo

commit sha bfb8b91719ac3f2405ac17f785df4407e8a4aa25

Auto merge of #26781 - servo:dependabot/cargo/tokio-io-0.1.13, r=jdm build(deps): bump tokio-io from 0.1.8 to 0.1.13 Bumps [tokio-io](https://github.com/tokio-rs/tokio) from 0.1.8 to 0.1.13. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/tokio-rs/tokio/blob/tokio-0.1.13/CHANGELOG.md">tokio-io's changelog</a>.</em></p> <blockquote> <h1>0.1.13 (November 21, 2018)</h1> <ul> <li>Fix <code>Runtime::reactor()</code> when no tasks are spawned (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/721">#721</a>).</li> <li><code>runtime::Builder</code> no longer uses deprecated methods (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/749">#749</a>).</li> <li>Provide <code>after_start</code> and <code>before_stop</code> configuration settings for <code>Runtime</code> (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/756">#756</a>).</li> <li>Implement throttle stream combinator (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/736">#736</a>).</li> </ul> <h1>0.1.12 (October 23, 2018)</h1> <ul> <li>runtime: expose <code>keep_alive</code> on runtime builder (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/676">#676</a>).</li> <li>runtime: create a reactor per worker thread (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/660">#660</a>).</li> <li>codec: fix panic in <code>LengthDelimitedCodec</code> (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/682">#682</a>).</li> <li>io: re-export <code>tokio_io::io::read</code> function (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/689">#689</a>).</li> <li>runtime: check for executor re-entry in more places (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/708">#708</a>).</li> </ul> <h1>0.1.11 (September 28, 2018)</h1> <ul> <li>Fix <code>tokio-async-await</code> dependency (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/675">#675</a>).</li> </ul> <h1>0.1.10 (September 27, 2018)</h1> <ul> <li>Fix minimal versions</li> </ul> <h1>0.1.9 (September 27, 2018)</h1> <ul> <li>Experimental async/await improvements (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/661">#661</a>).</li> <li>Re-export <code>TaskExecutor</code> from <code>tokio-current-thread</code> (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/652">#652</a>).</li> <li>Improve <code>Runtime</code> builder API (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/645">#645</a>).</li> <li><code>tokio::run</code> panics when called from the context of an executor (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/646">#646</a>).</li> <li>Introduce <code>StreamExt</code> with a <code>timeout</code> helper (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/573">#573</a>).</li> <li>Move <code>length_delimited</code> into <code>tokio</code> (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/575">#575</a>).</li> <li>Re-organize <code>tokio::net</code> module (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/548">#548</a>).</li> <li>Re-export <code>tokio-current-thread::spawn</code> in current_thread runtime (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/579">#579</a>).</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/tokio-rs/tokio/commit/b117fc1d65e72fa25eb0a921f77e5e2e0a8a49bb"><code>b117fc1</code></a> Bump version to v0.1.13 (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/771">#771</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/272e09d349b00e36303c12ed5ce9ba77ad2c4720"><code>272e09d</code></a> threadpool: remove smoke example (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/764">#764</a>) (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/770">#770</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/32357490067310bff74c9f94697d5974a570a834"><code>3235749</code></a> threadpool: refactor pool shutdown (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/769">#769</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/9c037044c4b837a7803be34c6d1a5e23d16011de"><code>9c03704</code></a> threadpool: rename inner to something more descriptive (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/768">#768</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/3658e10045664e816a65851d1e25c68965ec4359"><code>3658e10</code></a> uds: implement UnixDatagramFramed (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/453">#453</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/ed3ece266b5ab2ae3795a91d8dac25bc0fdfeec2"><code>ed3ece2</code></a> current-thread: fix shutdown on idle (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/763">#763</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/9b1a45cc6a15f5d2be17531dffc2f50d2b019646"><code>9b1a45c</code></a> tests: handle errors properly in examples (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/748">#748</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/477fa5580aa3796f97e3e0eb1325d4690b3b4e96"><code>477fa55</code></a> ci: Don't deploy docs if $TARGET is set (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/762">#762</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/bb6cca8ff0bd8ee3b9998cf2b0df58800eee39ae"><code>bb6cca8</code></a> tests: switch to Windows Server 2016 for AppVeyor builds. (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/761">#761</a>)</li> <li><a href="https://github.com/tokio-rs/tokio/commit/e166c4d91231c5af00df903b16b91c5c364f9b27"><code>e166c4d</code></a> Implement throttle combinator (<a href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/736">#736</a>)</li> <li>Additional commits viewable in <a href="https://github.com/tokio-rs/tokio/compare/tokio-io-0.1.8...tokio-0.1.13">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=tokio-io&package-manager=cargo&previous-version=0.1.8&new-version=0.1.13)](https://dependabot.com/compatibility-score/?dependency-name=tokio-io&package-manager=cargo&previous-version=0.1.8&new-version=0.1.13) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com): - Update frequency (including time of day and day of week) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) </details>

view details

Simon Sapin

commit sha 0abe90647f4548d0e35c8d9107b81e45ea739226

Remove support for energy profiling

view details

CYBAI

commit sha c561a3eb0e72a4d20f23eef2d61549284e6dd237

Introduce ElementCSSInlineStyle for SVGElement

view details

bors-servo

commit sha 5df062ab8852f9e4e48754efea6f5f4979d6ef85

Auto merge of #26779 - servo:dependabot/cargo/unicode-normalization-0.1.12, r=jdm build(deps): bump unicode-normalization from 0.1.5 to 0.1.12 Bumps [unicode-normalization](https://github.com/unicode-rs/unicode-normalization) from 0.1.5 to 0.1.12. <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/59febebedebd4df45ca5950f4e71fdf40e1da97d"><code>59febeb</code></a> Publish 0.1.12</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/fa604a6b99d4f04042214fae2a13ea3ed0435f15"><code>fa604a6</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/unicode-rs/unicode-normalization/issues/52">#52</a> from clintfred/master</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/91bd7d8c0b3a3e8e354f83da998c4345ccde4988"><code>91bd7d8</code></a> bump to smallvec 1.1.0</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/02f8b230b7a3aea4bb1433af4a24efbacb6ca8ea"><code>02f8b23</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/unicode-rs/unicode-normalization/issues/49">#49</a> from unicode-rs/bump</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/87fac9dafe8fda059b1e8f4b3eac18e9429b8a3a"><code>87fac9d</code></a> Bump to 0.1.11</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/d81a08a4eca0dd3120a0a9992b7922d3c412f6c5"><code>d81a08a</code></a> Add #[allow(ellipsis_inclusive_range_patterns)] to unicode.py</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/717e6c2dacfe44eb8b68267916e4c9ad44d9639f"><code>717e6c2</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/unicode-rs/unicode-normalization/issues/48">#48</a> from kentfredric/attempt-4</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/fc87399fceb1027eafed06ba19940fae0f7c50e3"><code>fc87399</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/unicode-rs/unicode-normalization/issues/47">#47</a> from unicode-rs/version-bump</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/5fabe3660c6f15fc2199b2ad2d6f07c6bdcaa468"><code>5fabe36</code></a> Bump to 0.1.10</li> <li><a href="https://github.com/unicode-rs/unicode-normalization/commit/0f4cb1e0b50a802ed891e2fcc3748fac2fdc075f"><code>0f4cb1e</code></a> Add travis glue to test built package too</li> <li>Additional commits viewable in <a href="https://github.com/unicode-rs/unicode-normalization/compare/v0.1.5...v0.1.12">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=unicode-normalization&package-manager=cargo&previous-version=0.1.5&new-version=0.1.12)](https://dependabot.com/compatibility-score/?dependency-name=unicode-normalization&package-manager=cargo&previous-version=0.1.5&new-version=0.1.12) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com): - Update frequency (including time of day and day of week) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) </details>

view details

bors-servo

commit sha 44811b020b5362b36503414b6c5cb161a833d01e

Auto merge of #26780 - servo:dependabot/cargo/proc-macro2-0.4.30, r=jdm build(deps): bump proc-macro2 from 0.4.26 to 0.4.30 Bumps [proc-macro2](https://github.com/alexcrichton/proc-macro2) from 0.4.26 to 0.4.30. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/alexcrichton/proc-macro2/releases">proc-macro2's releases</a>.</em></p> <blockquote> <h2>0.4.30</h2> <ul> <li>Implement Clone for TokenStream's IntoIter (<a href="https://github-redirect.dependabot.com/alexcrichton/proc-macro2/issues/177">#177</a>, thanks <a href="https://github.com/ivanbakel">@ivanbakel</a>)</li> </ul> <h2>0.4.29</h2> <ul> <li>Support compiling with <code>RUSTFLAGS='-Z allow-features='</code> on a nightly compiler (<a href="https://github-redirect.dependabot.com/alexcrichton/proc-macro2/issues/176">#176</a>, thanks <a href="https://github.com/Nemo157">@Nemo157</a>)</li> </ul> <h2>0.4.28</h2> <ul> <li>Avoid needlessly escaping <code>'</code> inside a string literal or <code>&quot;</code> inside a character literal (<a href="https://github-redirect.dependabot.com/alexcrichton/proc-macro2/issues/60">#60</a>)</li> <li>Add impls of Copy, Clone, Debug, PartialEq, Eq for proc_macro2::LineColumn</li> </ul> <h2>0.4.27</h2> <ul> <li> <p>Add Cargo cfg <code>&quot;span-locations&quot;</code> to expose <a href="https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html#method.start"><code>Span::start</code></a> and <a href="https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html#method.end"><code>Span::end</code></a> accessors that give the line and column location of a Span (<a href="https://github-redirect.dependabot.com/alexcrichton/proc-macro2/issues/166">#166</a>)</p> <p>Be aware that this involves storing more information than before inside of Spans which increases their size -- leading to possibly slower performance of any code involving proc-macro2 types (but only when the cfg is enabled).</p> </li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/f514921bb4405fea72b6289c200152f797d8b127"><code>f514921</code></a> Release 0.4.30</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/1ef4d12484af055284bec8651cab8ccda7c31f2a"><code>1ef4d12</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/alexcrichton/proc-macro2/issues/177">#177</a> from ivanbakel/cloneable_intoiter</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/f6754d35b25d0abde2309cd15e5dfe11c62597d9"><code>f6754d3</code></a> Make TokenStream's IntoIter derive Clone</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/79c8ed793f9afe4bc491575a86256651dcf777b6"><code>79c8ed7</code></a> Release 0.4.29</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/ce12a482f0365978e709c02c169fd45c8dbbe897"><code>ce12a48</code></a> Remove double negative in !proc_macro_span_disallowed</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/b455dd77647a2aeceba367527772ab9a111b64bf"><code>b455dd7</code></a> Use a cfg called proc_macro_span to control feature(proc_macro_span)</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/8a1827af91d09de6bdfa40041e73339131882726"><code>8a1827a</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/alexcrichton/proc-macro2/issues/176">#176</a> from Nemo157/block-nightly-feature</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/099db2afbbb1912be6510667d21505be3fa0a0ac"><code>099db2a</code></a> Detect if the user has disallowed usage of the proc_macro_span feature</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/692f49ce86afd0ef2a851f34ec5367d771c62d4f"><code>692f49c</code></a> Fix reference to Serde in contribution section</li> <li><a href="https://github.com/alexcrichton/proc-macro2/commit/16c2b45e92b54e7aedf1ff1e55238ff08b9cd948"><code>16c2b45</code></a> Release 0.4.28</li> <li>Additional commits viewable in <a href="https://github.com/alexcrichton/proc-macro2/compare/0.4.26...0.4.30">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=proc-macro2&package-manager=cargo&previous-version=0.4.26&new-version=0.4.30)](https://dependabot.com/compatibility-score/?dependency-name=proc-macro2&package-manager=cargo&previous-version=0.4.26&new-version=0.4.30) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com): - Update frequency (including time of day and day of week) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) </details>

view details

bors-servo

commit sha 5f6a05e71575f1d18650334fef1cd0d1985db839

Auto merge of #26771 - atouchet:raqote, r=jdm Update raqote and associated dependencies <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

view details

bors-servo

commit sha 97fd10c60244403b5011a1e7f8be83ec397e9d1b

Auto merge of #26784 - servo:dependabot/cargo/proc-macro-nested-0.1.4, r=jdm build(deps): bump proc-macro-nested from 0.1.3 to 0.1.4 Bumps [proc-macro-nested](https://github.com/dtolnay/proc-macro-hack) from 0.1.3 to 0.1.4. <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/dtolnay/proc-macro-hack/commits">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=proc-macro-nested&package-manager=cargo&previous-version=0.1.3&new-version=0.1.4)](https://dependabot.com/compatibility-score/?dependency-name=proc-macro-nested&package-manager=cargo&previous-version=0.1.3&new-version=0.1.4) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com): - Update frequency (including time of day and day of week) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) </details>

view details

bors-servo

commit sha e2d980a0712ffe59c20100c6120a199a769b41c1

Auto merge of #26480 - CYBAI:missing-on, r=jdm Prefix `on` for function name of inline events While checking what needs to be done for the spec-update, I've noticed the logic of checking `is window-reflecting element (e.g. body and frameset)` is already handled by the `is` casting function. However, we still failed to pass the tests because we're missing `on` prefix for inline functions. I'm not sure if this patch is good enough (or maybe at least I need to add a comment for why adding `on` prefix?). Besides, I checked [how Gecko handles](https://searchfox.org/mozilla-central/rev/8bc4e35c9bb47c1fe3131e6155d9f482e1efef9a/dom/events/EventListenerManager.cpp#1012-1022) and looks like they also just pass the atom directly. But, the [generated atom](https://searchfox.org/mozilla-central/source/__GENERATED__/xpcom/ds/nsGkAtomList.h#775) is prefixed with `on` which is correct to just pass it into the `CompileFunction`. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #26479 - [x] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

view details

Simon Sapin

commit sha b282bd3a441ce9a87c5cb4bddb0ce949afd5919b

Remove support for heartbeats profiling

view details

Simon Sapin

commit sha 3367db6067a8d76061e7884e54cc61ce44012442

Keep DOM proxy handlers as separate named items rather than in one array

view details

Simon Sapin

commit sha 57d89675b01b49c573b14c1fd0be413d52b8ccdd

Use atomic pointers instead of `static mut` for DOM proxy handlers

view details

Simon Sapin

commit sha dbdc44215b2b2acea193dba87a611ed045d9b9e2

Use UnsafeCell instead of `static mut` in background_hang_monitor/sampler_linux.rs

view details

bors-servo

commit sha 59ec134bb8b9562580b517a104868b7448e5f3f4

Auto merge of #26789 - CYBAI:svgelement-style, r=jdm Introduce ElementCSSInlineStyle for SVGElement --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #26777 and fix #26032 and fix #21990 - [x] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

view details

push time in 2 months

pull request commentrust-lang/rfcs

Edition 2021 and beyond

  • Every M years we have an edition.

In the N ≠ M variation, I’d tweak this to say at most every M years we have an edition (the compiler mode). If we have no migration ready to ship for more than M years there is no need for a new compiler mode. Within this there are two sub-variations:

  • The language team can decide to stabilize a new compiler mode in any 1.x version, as long as it’s been at least M years since the 1.y release that shipped the previous compiler mode. The number M only serves to put a limit on churn.

  • Or we preserve a train model of having an opportunity to stabilize a new compiler mode on a regular cadence every M years, but skip trains when there is no migration ready and waiting.

Shorthand to mean "up to date with modern idioms"

The module system is really an exception here. This RFC itself says we don’t expect to make such big migrations again.

Except for modules "up to date with modern idioms" is largely independent from the compiler mode. The ? operator, impl Trait, and the '_ lifetime can all be used with edition = "2015".

I do sort of like the idea of motivating people to upgrade

Why? Not making the upgrade mandatory for every crate is a key part of the system.

If we release an edition early in the year, it's easy to imagine that this will get a lot of play, and perhaps the retrospective will not seem as exciting ("meh, it's just covering old news").

I don’t think that’s necessarily the case. An hypothetical new compiler mode that does nothing but reserve a couple keywords is not that exciting.

nikomatsakis

comment created time in 3 months

issue commentvector-im/element-web

Support Custom CSS Stylesheet

there is a config.json somewhere. it might a) be deep in the files kinda hidden behind all the electron stuff or b) inside a asar file (which essentially is just a zip with a fancy name).

Both of those are kinda user-hostile. It would be nice to make this file more easily editable by users without risk of it being overwritten in an update.

chresan

comment created time in 3 months

issue commentrust-lang/wg-allocators

Replace `MemoryBlock` with `NonNull<[u8]>`

@zakarumych Closed issues are generally not a great place to ask a question since they’re considered resolved and not in need of attention anymore.

&mut [MaybeUninit<u8>] was discussed in https://github.com/rust-lang/wg-allocators/issues/65. It’s really two proposals: &mut instead of NonNull, and MaybeUninit<u8> instead of u8. The former has the problem that we’d need to pick a lifetime for that reference, and none is accurate since the actual life time of a heap allocation is dynamic and cannot be encoded statically in the borrow checked. MaybeUninit is being discussed in https://github.com/rust-lang/wg-allocators/issues/66.

SimonSapin

comment created time in 3 months

pull request commentservo/servo

2020: Implement table map construction

I don’t have an opinion on CellMap v.s. TableSlots but let’s pick one name :)

Manishearth

comment created time in 3 months

Pull request review commentservo/servo

2020: Implement table map construction

+/* This Source Code Form is subject to the terms of the Mozilla Public+ * License, v. 2.0. If a copy of the MPL was not distributed with this+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */+

This is implementing https://html.spec.whatwg.org/multipage/tables.html#table-processing-model, right? Let’s have a link in a comment near the top of the file.

Manishearth

comment created time in 3 months

Pull request review commentservo/servo

2020: Implement table map construction

+/* This Source Code Form is subject to the terms of the Mozilla Public+ * License, v. 2.0. If a copy of the MPL was not distributed with this+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */++use super::TableContainer;+use crate::context::LayoutContext;+use crate::dom_traversal::{+    BoxSlot, Contents, NodeAndStyleInfo, NodeExt, NonReplacedContents, TraversalHandler,+};+use crate::style_ext::{DisplayGeneratingBox, DisplayInternal};+use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode;+use std::borrow::Cow;+use std::cmp;+use std::convert::TryFrom;+use std::fmt;+use style::values::specified::text::TextDecorationLine;++#[derive(Debug, Default, Serialize)]+/// A map of table slots to cells+pub(crate) struct TableSlots {+    rows: Vec<TableSlotsRow>,+}++#[derive(Debug, Default, Serialize)]+/// A row in the table slot map+pub(crate) struct TableSlotsRow {+    cells: Vec<TableSlot>,+}++impl TableSlots {+    /// Get the slot at (x, y)+    pub fn get(&self, x: usize, y: usize) -> Option<&TableSlot> {+        self.rows.get(y)?.cells.get(x)+    }++    /// Inserts a new slot into the last row+    fn push(&mut self, slot: TableSlot) {+        let y = self.rows.len() - 1;+        self.rows[y].cells.push(slot)+    }++    /// Convenience method for get() that returns a SlotAndLocation+    fn get_loc(&self, x: usize, y: usize) -> Option<SlotAndLocation> {+        self.rows+            .get(y)?+            .cells+            .get(x)+            .map(|slot| SlotAndLocation { slot, x, y })+    }++    /// Get the slot from the previous row at x+    fn get_above(&self, x: usize) -> Option<SlotAndLocation> {+        if self.rows.len() > 1 {+            self.get_loc(x, self.rows.len() - 2)+        } else {+            None+        }+    }++    /// Given a slot and location, find the originating TableSlot::Cell.+    /// In the case of a table model error, there may be multiple, returning+    /// the oldest cell first+    fn resolve_slot<'a>(+        &'a self,+        location: SlotAndLocation<'a>,+    ) -> (SlotAndLocation<'a>, Vec<SlotAndLocation<'a>>) {+        match *location.slot {+            TableSlot::Cell { .. } => (location, Vec::new()),+            TableSlot::Spanned(x, y) => (+                self.get_loc(location.x - x, location.y - y)+                    .expect("Spanned slot reference must resolve"),+                Vec::new(),+            ),+            TableSlot::MultiSpanned(ref vec) => {+                let mut v: Vec<_> = vec+                    .iter()+                    .map(|(x, y)| {+                        self.get_loc(location.x - x, location.y - y)+                            .expect("Spanned slot reference must resolve")+                    })+                    .collect();+                (v.pop().unwrap(), v)+            },+            TableSlot::Empty => {+                panic!("Should never attempt to resolve an empty slot");+            },+        }+    }++    /// If (x, y) is spanned by an already resolved `spanner`, return offsets for a TableSlot::Spanned() for it+    fn spanned_slot_single(+        &self,+        x: usize,+        y: usize,+        spanner: SlotAndLocation,+    ) -> Option<(usize, usize)> {+        if let TableSlot::Cell { width, height, .. } = spanner.slot {+            if x >= spanner.x && y >= spanner.y && x < spanner.x + *width {+                if *height == 0 || y < spanner.y + *height {+                    Some((x - spanner.x, y - spanner.y))+                } else {+                    None+                }+            } else {+                None+            }+        } else {+            panic!("spanned_slot_single cannot be called with a non-resolved slot")+        }+    }++    /// If (x, y) is spanned by the resolution of `spanner`, return a+    /// TableSlot::Spanned() or TableSlot::MultiSpanned() for it+    fn spanned_slot(&self, x: usize, y: usize, spanner: SlotAndLocation) -> Option<TableSlot> {+        let resolved = self.resolve_slot(spanner);+        if resolved.1.is_empty() {+            self.spanned_slot_single(x, y, resolved.0)+                .map(|spanned| TableSlot::Spanned(spanned.0, spanned.1))+        } else {+            let mut vec = resolved.1;+            vec.push(resolved.0);++            let coordinates: Vec<_> = vec+                .into_iter()+                .filter_map(|slot| self.spanned_slot_single(x, y, slot))+                .collect();+            if coordinates.is_empty() {+                return None;+            }++            if coordinates.len() == 1 {+                Some(TableSlot::Spanned(coordinates[0].0, coordinates[0].1))+            } else {+                Some(TableSlot::MultiSpanned(coordinates))+            }+        }+    }+}++// A reference to a slot and its coordinates in the table+#[derive(Clone, Copy, Debug)]+struct SlotAndLocation<'a> {+    slot: &'a TableSlot,+    x: usize,+    y: usize,+}++#[derive(Serialize)]+/// A single table slot. It may be an actual cell, or a reference+/// to a previous cell that is spanned here+///+/// In case of table model errors, it may be multiple references+pub(crate) enum TableSlot {+    /// A table cell, with a width and height+    Cell {+        cell: TableCellBox,+        /// the width of the cell+        width: usize,+        /// the height of the cell (0 for rowspan=0)+        // XXXManishearth should we fixup rowspan=0 later?+        height: usize,+    },+    /// This slot is spanned by the cell at offset (-x, -y)+    Spanned(usize, usize),+    /// This slot is spanned by multiple cells at the given negative coordinate offsets. Oops.+    /// This is a table model error, but we still keep track of it+    /// https://html.spec.whatwg.org/multipage/#table-model-error+    ///+    /// The Vec is in the order of newest to oldest cell+    MultiSpanned(Vec<(usize, usize)>),++    /// There's nothing here+    /// Only exists when there's a rowspan coming up+    Empty,+}++impl TableSlot {+    /// Assuming this is a TableSlot::Spanned, get the coordinates+    pub fn as_spanned(&self) -> (usize, usize) {+        if let TableSlot::Spanned(x, y) = *self {+            (x, y)+        } else {+            panic!("TableSlot::as_spanned called with a non-Spanned TableSlot")+        }+    }++    /// Merge a TableSlot::Spanned(x, y) with this (only for model errors)+    pub fn push_spanned(&mut self, x: usize, y: usize) {+        match *self {+            TableSlot::Cell {..} => {+                panic!("Should never have a table model error with an originating cell slot overlapping a spanned slot")+            }+            TableSlot::Spanned(x1, y1) => {+                *self = TableSlot::MultiSpanned(vec![(x, y), (x1, y1)])+            }+            TableSlot::MultiSpanned(ref mut vec) => vec.insert(0, (x, y)),+            TableSlot::Empty => {+                panic!("Should never have a table model error with an empty slot");+            }+        }+    }+}++impl fmt::Debug for TableSlot {+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {+        match *self {+            TableSlot::Cell { width, height, .. } => write!(f, "Cell({}, {})", width, height),+            TableSlot::Spanned(x, y) => write!(f, "Spanned({}, {})", x, y),+            TableSlot::MultiSpanned(ref vec) => write!(f, "MultiSpanned({:?})", vec),+            TableSlot::Empty => write!(f, "Empty"),+        }+    }+}++#[derive(Debug, Serialize)]+pub(crate) struct TableCellBox {}++struct TableContainerBuilder<'a, Node> {+    context: &'a LayoutContext<'a>,+    info: &'a NodeAndStyleInfo<Node>,+    slots: TableSlots,+    /// If there is an incoming rowspanned cell in this column,+    /// this value will be nonzero. Positive values indicate the number of+    /// rows that still need to be spanned. Negative values indicate rowspan=0+    ///+    /// This vector is reused for the outgoing rowspans, if there is already a cell+    /// in the cell map the value in this array represents the incoming rowspan for the *next* row+    incoming_rowspans: Vec<isize>,+}++impl TableContainer {+    pub fn construct<'dom>(+        context: &LayoutContext,+        info: &NodeAndStyleInfo<impl NodeExt<'dom>>,+        contents: NonReplacedContents,+        // XXXManishearth is this useful?+        _propagated_text_decoration_line: TextDecorationLine,+    ) -> Self {+        let mut builder = TableContainerBuilder::new(context, info);+        contents.traverse(context, info, &mut builder);+        TableContainer {}+    }+}++impl<'a, Node> TableContainerBuilder<'a, Node> {+    fn new(context: &'a LayoutContext, info: &'a NodeAndStyleInfo<Node>) -> Self {+        TableContainerBuilder {+            context,+            info,+            slots: TableSlots::default(),+            incoming_rowspans: Vec::new(),+        }+    }++    fn current_y(&self) -> usize {+        self.slots.rows.len() - 1+    }+}++impl<'a, 'dom, Node: 'dom> TraversalHandler<'dom, Node> for TableContainerBuilder<'a, Node>+where+    Node: NodeExt<'dom>,+{+    fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>) {+        // TODO: this might need to be wrapped in something+    }++    /// https://html.spec.whatwg.org/multipage/#forming-a-table+    fn handle_element(+        &mut self,+        info: &NodeAndStyleInfo<Node>,+        display: DisplayGeneratingBox,+        contents: Contents,+        box_slot: BoxSlot<'dom>,+    ) {+        match display {+            DisplayGeneratingBox::Internal(i) => match i {+                DisplayInternal::TableRowGroup => {+                    // XXXManishearth maybe fixup `width=0` to the actual resolved value+                    // and any other rowspans that have been cut short+                    self.incoming_rowspans.clear();+                    NonReplacedContents::try_from(contents).unwrap().traverse(+                        self.context,+                        info,+                        self,+                    );++                    // XXXManishearth push some kind of row group box somewhere+                },+                DisplayInternal::TableRow => {+                    let context = self.context;+                    // XXXManishearth use with_capacity+                    self.slots.rows.push(TableSlotsRow::default());+                    let mut row_builder = TableRowBuilder::new(self);+                    row_builder.consume_rowspans(true);+                    NonReplacedContents::try_from(contents).unwrap().traverse(+                        context,+                        info,+                        &mut row_builder,+                    );+                    row_builder.truncate_incoming_rowspans();+                    row_builder.consume_rowspans(false);++                    // XXXManishearth push some kind of row box somewhere+                },+                _ => (),+                // XXXManishearth handle colgroups/etc+                // XXXManishearth handle unparented cells ?+                // XXXManishearth handle captions+            },+            _ => {+                // TODO this might need to be wrapped+            },+        }+        ::std::mem::forget(box_slot)+        // do something?+    }+}++struct TableRowBuilder<'a, 'builder, Node> {+    builder: &'builder mut TableContainerBuilder<'a, Node>,+}++impl<'a, 'builder, Node> TableRowBuilder<'a, 'builder, Node> {+    fn new(builder: &'builder mut TableContainerBuilder<'a, Node>) -> Self {+        TableRowBuilder { builder }+    }++    fn current_x(&self) -> usize {+        self.builder.slots.rows[self.builder.current_y()]+            .cells+            .len()+    }+}++impl<'a, 'builder, 'dom, Node: 'dom> TraversalHandler<'dom, Node>+    for TableRowBuilder<'a, 'builder, Node>+where+    Node: NodeExt<'dom>,+{+    fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>) {+        // TODO: this might need to be wrapped in something+    }++    /// https://html.spec.whatwg.org/multipage/#algorithm-for-processing-rows+    fn handle_element(+        &mut self,+        info: &NodeAndStyleInfo<Node>,+        display: DisplayGeneratingBox,+        contents: Contents,+        box_slot: BoxSlot<'dom>,+    ) {+        match display {+            DisplayGeneratingBox::Internal(i) => match i {+                DisplayInternal::TableCell => {+                    self.handle_cell(&info);+                    self.consume_rowspans(true);+                    // XXXManishearth this will not handle any leftover incoming rowspans+                    // after all cells are processed, we need to introduce TableSlot::None+                },+                _ => (), // XXXManishearth handle unparented row groups/etc ?+            },+            _ => {+                // TODO this might need to be wrapped+            },+        }+        ::std::mem::forget(box_slot)+        // do something?+    }+}++impl<'a, 'builder, 'dom, Node> TableRowBuilder<'a, 'builder, Node>+where+    Node: NodeExt<'dom>,+{+    /// When not in the process of filling a cell, make sure any incoming rowspans are+    /// filled so that the next specified cell comes after them. Should have been called before+    /// handle_cell+    ///+    /// if stop_at_zero is set,

Looks you like meant to write some more here?

Manishearth

comment created time in 3 months

Pull request review commentservo/servo

2020: Implement table map construction

+/* This Source Code Form is subject to the terms of the Mozilla Public+ * License, v. 2.0. If a copy of the MPL was not distributed with this+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */++use super::TableContainer;+use crate::context::LayoutContext;+use crate::dom_traversal::{+    BoxSlot, Contents, NodeAndStyleInfo, NodeExt, NonReplacedContents, TraversalHandler,+};+use crate::style_ext::{DisplayGeneratingBox, DisplayInternal};+use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode;+use std::borrow::Cow;+use std::cmp;+use std::convert::TryFrom;+use std::fmt;+use style::values::specified::text::TextDecorationLine;++#[derive(Debug, Default, Serialize)]+/// A map of table slots to cells+pub(crate) struct TableSlots {+    rows: Vec<TableSlotsRow>,+}++#[derive(Debug, Default, Serialize)]+/// A row in the table slot map+pub(crate) struct TableSlotsRow {+    cells: Vec<TableSlot>,+}++impl TableSlots {+    /// Get the slot at (x, y)+    pub fn get(&self, x: usize, y: usize) -> Option<&TableSlot> {+        self.rows.get(y)?.cells.get(x)+    }++    /// Inserts a new slot into the last row+    fn push(&mut self, slot: TableSlot) {+        let y = self.rows.len() - 1;+        self.rows[y].cells.push(slot)+    }++    /// Convenience method for get() that returns a SlotAndLocation+    fn get_loc(&self, x: usize, y: usize) -> Option<SlotAndLocation> {+        self.rows+            .get(y)?+            .cells+            .get(x)+            .map(|slot| SlotAndLocation { slot, x, y })+    }++    /// Get the slot from the previous row at x+    fn get_above(&self, x: usize) -> Option<SlotAndLocation> {+        if self.rows.len() > 1 {+            self.get_loc(x, self.rows.len() - 2)+        } else {+            None+        }+    }++    /// Given a slot and location, find the originating TableSlot::Cell.+    /// In the case of a table model error, there may be multiple, returning+    /// the oldest cell first+    fn resolve_slot<'a>(+        &'a self,+        location: SlotAndLocation<'a>,+    ) -> (SlotAndLocation<'a>, Vec<SlotAndLocation<'a>>) {+        match *location.slot {+            TableSlot::Cell { .. } => (location, Vec::new()),+            TableSlot::Spanned(x, y) => (+                self.get_loc(location.x - x, location.y - y)+                    .expect("Spanned slot reference must resolve"),+                Vec::new(),+            ),+            TableSlot::MultiSpanned(ref vec) => {+                let mut v: Vec<_> = vec+                    .iter()+                    .map(|(x, y)| {+                        self.get_loc(location.x - x, location.y - y)+                            .expect("Spanned slot reference must resolve")+                    })+                    .collect();+                (v.pop().unwrap(), v)+            },+            TableSlot::Empty => {+                panic!("Should never attempt to resolve an empty slot");+            },+        }+    }++    /// If (x, y) is spanned by an already resolved `spanner`, return offsets for a TableSlot::Spanned() for it+    fn spanned_slot_single(+        &self,+        x: usize,+        y: usize,+        spanner: SlotAndLocation,+    ) -> Option<(usize, usize)> {+        if let TableSlot::Cell { width, height, .. } = spanner.slot {+            if x >= spanner.x && y >= spanner.y && x < spanner.x + *width {+                if *height == 0 || y < spanner.y + *height {+                    Some((x - spanner.x, y - spanner.y))+                } else {+                    None+                }+            } else {+                None+            }+        } else {+            panic!("spanned_slot_single cannot be called with a non-resolved slot")+        }+    }++    /// If (x, y) is spanned by the resolution of `spanner`, return a+    /// TableSlot::Spanned() or TableSlot::MultiSpanned() for it+    fn spanned_slot(&self, x: usize, y: usize, spanner: SlotAndLocation) -> Option<TableSlot> {+        let resolved = self.resolve_slot(spanner);

Nit: I’d prefer to have tuple destructuring here to name the components instead of having .0 and .1 later

Manishearth

comment created time in 3 months

Pull request review commentservo/servo

2020: Implement table map construction

+/* This Source Code Form is subject to the terms of the Mozilla Public+ * License, v. 2.0. If a copy of the MPL was not distributed with this+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */++use super::TableContainer;+use crate::context::LayoutContext;+use crate::dom_traversal::{+    BoxSlot, Contents, NodeAndStyleInfo, NodeExt, NonReplacedContents, TraversalHandler,+};+use crate::style_ext::{DisplayGeneratingBox, DisplayInternal};+use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode;+use std::borrow::Cow;+use std::cmp;+use std::convert::TryFrom;+use std::fmt;+use style::values::specified::text::TextDecorationLine;++#[derive(Debug, Default, Serialize)]+/// A map of table slots to cells+pub(crate) struct TableSlots {+    rows: Vec<TableSlotsRow>,+}++#[derive(Debug, Default, Serialize)]+/// A row in the table slot map+pub(crate) struct TableSlotsRow {+    cells: Vec<TableSlot>,+}++impl TableSlots {+    /// Get the slot at (x, y)+    pub fn get(&self, x: usize, y: usize) -> Option<&TableSlot> {+        self.rows.get(y)?.cells.get(x)+    }++    /// Inserts a new slot into the last row+    fn push(&mut self, slot: TableSlot) {+        let y = self.rows.len() - 1;+        self.rows[y].cells.push(slot)+    }++    /// Convenience method for get() that returns a SlotAndLocation+    fn get_loc(&self, x: usize, y: usize) -> Option<SlotAndLocation> {+        self.rows+            .get(y)?+            .cells+            .get(x)+            .map(|slot| SlotAndLocation { slot, x, y })+    }++    /// Get the slot from the previous row at x+    fn get_above(&self, x: usize) -> Option<SlotAndLocation> {+        if self.rows.len() > 1 {+            self.get_loc(x, self.rows.len() - 2)+        } else {+            None+        }+    }++    /// Given a slot and location, find the originating TableSlot::Cell.+    /// In the case of a table model error, there may be multiple, returning+    /// the oldest cell first+    fn resolve_slot<'a>(+        &'a self,+        location: SlotAndLocation<'a>,+    ) -> (SlotAndLocation<'a>, Vec<SlotAndLocation<'a>>) {+        match *location.slot {+            TableSlot::Cell { .. } => (location, Vec::new()),+            TableSlot::Spanned(x, y) => (+                self.get_loc(location.x - x, location.y - y)+                    .expect("Spanned slot reference must resolve"),+                Vec::new(),+            ),+            TableSlot::MultiSpanned(ref vec) => {+                let mut v: Vec<_> = vec+                    .iter()+                    .map(|(x, y)| {+                        self.get_loc(location.x - x, location.y - y)+                            .expect("Spanned slot reference must resolve")+                    })+                    .collect();+                (v.pop().unwrap(), v)+            },+            TableSlot::Empty => {+                panic!("Should never attempt to resolve an empty slot");+            },+        }+    }++    /// If (x, y) is spanned by an already resolved `spanner`, return offsets for a TableSlot::Spanned() for it+    fn spanned_slot_single(+        &self,+        x: usize,+        y: usize,+        spanner: SlotAndLocation,+    ) -> Option<(usize, usize)> {+        if let TableSlot::Cell { width, height, .. } = spanner.slot {+            if x >= spanner.x && y >= spanner.y && x < spanner.x + *width {+                if *height == 0 || y < spanner.y + *height {+                    Some((x - spanner.x, y - spanner.y))+                } else {+                    None+                }+            } else {+                None+            }+        } else {+            panic!("spanned_slot_single cannot be called with a non-resolved slot")+        }+    }++    /// If (x, y) is spanned by the resolution of `spanner`, return a+    /// TableSlot::Spanned() or TableSlot::MultiSpanned() for it+    fn spanned_slot(&self, x: usize, y: usize, spanner: SlotAndLocation) -> Option<TableSlot> {+        let resolved = self.resolve_slot(spanner);+        if resolved.1.is_empty() {+            self.spanned_slot_single(x, y, resolved.0)+                .map(|spanned| TableSlot::Spanned(spanned.0, spanned.1))+        } else {+            let mut vec = resolved.1;+            vec.push(resolved.0);++            let coordinates: Vec<_> = vec+                .into_iter()+                .filter_map(|slot| self.spanned_slot_single(x, y, slot))+                .collect();+            if coordinates.is_empty() {+                return None;+            }++            if coordinates.len() == 1 {+                Some(TableSlot::Spanned(coordinates[0].0, coordinates[0].1))+            } else {+                Some(TableSlot::MultiSpanned(coordinates))+            }+        }+    }+}++// A reference to a slot and its coordinates in the table+#[derive(Clone, Copy, Debug)]+struct SlotAndLocation<'a> {+    slot: &'a TableSlot,+    x: usize,+    y: usize,+}++#[derive(Serialize)]+/// A single table slot. It may be an actual cell, or a reference+/// to a previous cell that is spanned here+///+/// In case of table model errors, it may be multiple references+pub(crate) enum TableSlot {+    /// A table cell, with a width and height+    Cell {+        cell: TableCellBox,+        /// the width of the cell+        width: usize,+        /// the height of the cell (0 for rowspan=0)+        // XXXManishearth should we fixup rowspan=0 later?+        height: usize,+    },+    /// This slot is spanned by the cell at offset (-x, -y)+    Spanned(usize, usize),+    /// This slot is spanned by multiple cells at the given negative coordinate offsets. Oops.+    /// This is a table model error, but we still keep track of it+    /// https://html.spec.whatwg.org/multipage/#table-model-error+    ///+    /// The Vec is in the order of newest to oldest cell+    MultiSpanned(Vec<(usize, usize)>),++    /// There's nothing here+    /// Only exists when there's a rowspan coming up+    Empty,+}++impl TableSlot {+    /// Assuming this is a TableSlot::Spanned, get the coordinates+    pub fn as_spanned(&self) -> (usize, usize) {+        if let TableSlot::Spanned(x, y) = *self {+            (x, y)+        } else {+            panic!("TableSlot::as_spanned called with a non-Spanned TableSlot")+        }+    }++    /// Merge a TableSlot::Spanned(x, y) with this (only for model errors)+    pub fn push_spanned(&mut self, x: usize, y: usize) {+        match *self {+            TableSlot::Cell {..} => {+                panic!("Should never have a table model error with an originating cell slot overlapping a spanned slot")+            }+            TableSlot::Spanned(x1, y1) => {+                *self = TableSlot::MultiSpanned(vec![(x, y), (x1, y1)])+            }+            TableSlot::MultiSpanned(ref mut vec) => vec.insert(0, (x, y)),+            TableSlot::Empty => {+                panic!("Should never have a table model error with an empty slot");+            }+        }+    }+}++impl fmt::Debug for TableSlot {+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {+        match *self {+            TableSlot::Cell { width, height, .. } => write!(f, "Cell({}, {})", width, height),+            TableSlot::Spanned(x, y) => write!(f, "Spanned({}, {})", x, y),+            TableSlot::MultiSpanned(ref vec) => write!(f, "MultiSpanned({:?})", vec),+            TableSlot::Empty => write!(f, "Empty"),+        }+    }+}++#[derive(Debug, Serialize)]+pub(crate) struct TableCellBox {}++struct TableContainerBuilder<'a, Node> {+    context: &'a LayoutContext<'a>,+    info: &'a NodeAndStyleInfo<Node>,+    slots: TableSlots,+    /// If there is an incoming rowspanned cell in this column,+    /// this value will be nonzero. Positive values indicate the number of+    /// rows that still need to be spanned. Negative values indicate rowspan=0+    ///+    /// This vector is reused for the outgoing rowspans, if there is already a cell+    /// in the cell map the value in this array represents the incoming rowspan for the *next* row+    incoming_rowspans: Vec<isize>,+}++impl TableContainer {+    pub fn construct<'dom>(+        context: &LayoutContext,+        info: &NodeAndStyleInfo<impl NodeExt<'dom>>,+        contents: NonReplacedContents,+        // XXXManishearth is this useful?+        _propagated_text_decoration_line: TextDecorationLine,

It will be when we start constructing boxes for the contents of table cells etc.

Manishearth

comment created time in 3 months

more