mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
121725038a
27
Cargo.lock
generated
27
Cargo.lock
generated
@ -819,6 +819,19 @@ dependencies = [
|
||||
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper_serde"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.0"
|
||||
@ -966,10 +979,14 @@ dependencies = [
|
||||
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashglobe 0.1.0",
|
||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.19.0",
|
||||
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_arc 0.1.1",
|
||||
"smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1574,6 +1591,14 @@ dependencies = [
|
||||
"serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.35"
|
||||
@ -2294,6 +2319,7 @@ dependencies = [
|
||||
"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
|
||||
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
|
||||
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
|
||||
"checksum hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0997ad463f64ce6ba02cf5af320622bb9782e4f8355b650a2cc7ccca69a7cc2e"
|
||||
"checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
|
||||
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
||||
"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
|
||||
@ -2368,6 +2394,7 @@ dependencies = [
|
||||
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "800fdb0a894572994f3970035a8a5f65d8ec2cd40e6cdf7d8cd9001d7b30648e"
|
||||
"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"
|
||||
"checksum serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
|
||||
"checksum serde_derive_internals 0.22.1 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
|
||||
"checksum simd 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd0805c7363ab51a829a1511ad24b6ed0349feaa756c4bc2f977f9f496e6673"
|
||||
|
@ -474,6 +474,13 @@ var Policies = {
|
||||
}
|
||||
},
|
||||
|
||||
"OverrideFirstRunPage": {
|
||||
onProfileAfterChange(manager, param) {
|
||||
let url = param ? param.spec : "";
|
||||
setAndLockPref("startup.homepage_welcome_url", url);
|
||||
}
|
||||
},
|
||||
|
||||
"PopupBlocking": {
|
||||
onBeforeUIStartup(manager, param) {
|
||||
addAllowDenyPermissions("popup", param.Allow, null);
|
||||
|
@ -350,6 +350,14 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"OverrideFirstRunPage": {
|
||||
"description": "Override the first run page. Set this policy to blank if you want to disable the first run page.",
|
||||
"first_available": "60.0",
|
||||
"enterprise_only": true,
|
||||
|
||||
"type": "URLorEmpty"
|
||||
},
|
||||
|
||||
"PopupBlocking": {
|
||||
"description": "Allow or deny popup usage.",
|
||||
"first_available": "60.0",
|
||||
|
@ -69,6 +69,12 @@ const POLICIES_TESTS = [
|
||||
"privacy.trackingprotection.pbmode.enabled": false,
|
||||
}
|
||||
},
|
||||
|
||||
// POLICY: OverrideFirstRunPage
|
||||
{
|
||||
policies: { "OverrideFirstRunPage": "https://www.example.com/" },
|
||||
lockedPrefs: { "startup.homepage_welcome_url": "https://www.example.com/" },
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function test_policy_remember_passwords() {
|
||||
|
@ -729,7 +729,8 @@ exports.CSS_PROPERTIES = {
|
||||
"column-gap"
|
||||
],
|
||||
"supports": [
|
||||
6
|
||||
6,
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"calc",
|
||||
@ -2081,6 +2082,7 @@ exports.CSS_PROPERTIES = {
|
||||
"-moz-min-content",
|
||||
"auto",
|
||||
"calc",
|
||||
"content",
|
||||
"inherit",
|
||||
"initial",
|
||||
"unset"
|
||||
@ -2102,6 +2104,7 @@ exports.CSS_PROPERTIES = {
|
||||
"-moz-min-content",
|
||||
"auto",
|
||||
"calc",
|
||||
"content",
|
||||
"inherit",
|
||||
"initial",
|
||||
"unset"
|
||||
@ -5118,7 +5121,8 @@ exports.CSS_PROPERTIES = {
|
||||
"column-gap"
|
||||
],
|
||||
"supports": [
|
||||
6
|
||||
6,
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"calc",
|
||||
@ -5547,6 +5551,7 @@ exports.CSS_PROPERTIES = {
|
||||
"-moz-min-content",
|
||||
"auto",
|
||||
"calc",
|
||||
"content",
|
||||
"inherit",
|
||||
"initial",
|
||||
"unset"
|
||||
@ -5568,6 +5573,7 @@ exports.CSS_PROPERTIES = {
|
||||
"-moz-min-content",
|
||||
"auto",
|
||||
"calc",
|
||||
"content",
|
||||
"inherit",
|
||||
"initial",
|
||||
"unset"
|
||||
|
@ -52,9 +52,9 @@ div {
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function getDocShellForObservingRestyles() {
|
||||
function getDocShellForObservingRestylesForWindow(aWindow) {
|
||||
const docShell =
|
||||
SpecialPowers.wrap(window)
|
||||
SpecialPowers.wrap(aWindow)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIDocShell);
|
||||
@ -66,16 +66,22 @@ function getDocShellForObservingRestyles() {
|
||||
}
|
||||
|
||||
// Returns the animation restyle markers observed during |frameCount| refresh
|
||||
// driver ticks. This function is typically used to count the number of
|
||||
// restyles that take place as part of the style update that happens on each
|
||||
// refresh driver tick, as opposed to synchronous restyles triggered by script.
|
||||
// driver ticks in this `window`. This function is typically used to count the
|
||||
// number of restyles that take place as part of the style update that happens
|
||||
// on each refresh driver tick, as opposed to synchronous restyles triggered by
|
||||
// script.
|
||||
//
|
||||
// For the latter observeAnimSyncStyling (below) should be used.
|
||||
function observeStyling(frameCount, onFrame) {
|
||||
let docShell = getDocShellForObservingRestyles();
|
||||
return observeStylingInTargetWindow(window, frameCount, onFrame);
|
||||
}
|
||||
|
||||
// As with observeStyling but applied to target window |aWindow|.
|
||||
function observeStylingInTargetWindow(aWindow, aFrameCount, aOnFrame) {
|
||||
let docShell = getDocShellForObservingRestylesForWindow(aWindow);
|
||||
|
||||
return new Promise(resolve => {
|
||||
return waitForAnimationFrames(frameCount, onFrame).then(() => {
|
||||
return waitForAnimationFrames(aFrameCount, aOnFrame).then(() => {
|
||||
var markers = docShell.popProfileTimelineMarkers();
|
||||
docShell.recordProfileTimelineMarkers = false;
|
||||
var stylingMarkers = markers.filter((marker, index) => {
|
||||
@ -93,7 +99,7 @@ function observeStyling(frameCount, onFrame) {
|
||||
// |funcToMakeRestyleHappen|, which may be expected to trigger a synchronous
|
||||
// restyles, and returns any restyle markers produced by calling that function.
|
||||
function observeAnimSyncStyling(funcToMakeRestyleHappen) {
|
||||
let docShell = getDocShellForObservingRestyles();
|
||||
let docShell = getDocShellForObservingRestylesForWindow(window);
|
||||
|
||||
funcToMakeRestyleHappen();
|
||||
|
||||
@ -1639,6 +1645,78 @@ waitForAllPaints(() => {
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
async function throttling_position_absolute_animations_in_collapsed_iframe() {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('srcdoc', '<div id="target"></div>');
|
||||
iframe.style.height = '0px';
|
||||
document.documentElement.appendChild(iframe);
|
||||
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener('load', () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const target = iframe.contentDocument.getElementById("target");
|
||||
target.style= 'position: absolute; top: 50%; width: 100px; height: 100px';
|
||||
|
||||
var animation = target.animate({ opacity: [0, 1] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
iterations: Infinity });
|
||||
await animation.ready;
|
||||
|
||||
var markers = await observeStylingInTargetWindow(iframe.contentWindow, 5);
|
||||
is(markers.length, 0,
|
||||
'Animation on position:absolute element in collapsed iframe should ' +
|
||||
'be throttled');
|
||||
|
||||
await ensureElementRemoval(iframe);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
async function position_absolute_animations_in_collapsed_element() {
|
||||
var parent = addDiv(null, { style: 'overflow: scroll; height: 0px;' });
|
||||
var target = addDiv(null,
|
||||
{ style: 'animation: background-color 100s infinite;' +
|
||||
'position: absolute; top: 50%;' +
|
||||
'width: 100px; height: 100px;' });
|
||||
parent.appendChild(target);
|
||||
|
||||
var animation = target.getAnimations()[0];
|
||||
await animation.ready;
|
||||
|
||||
const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
|
||||
var markers = await observeStyling(5);
|
||||
is(markers.length, expectedRestyleCount,
|
||||
'Animation on position:absolute element in collapsed element ' +
|
||||
'should not be throttled');
|
||||
|
||||
await ensureElementRemoval(parent);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
async function throttling_position_absolute_animations_in_collapsed_element() {
|
||||
var parent = addDiv(null, { style: 'overflow: scroll; height: 0px;' });
|
||||
var target = addDiv(null,
|
||||
{ style: 'animation: background-color 100s infinite;' +
|
||||
'position: absolute; top: 50%;' });
|
||||
parent.appendChild(target);
|
||||
|
||||
var animation = target.getAnimations()[0];
|
||||
await animation.ready;
|
||||
|
||||
var markers = await observeStyling(5);
|
||||
todo_is(markers.length, 0,
|
||||
'Animation on collapsed position:absolute element in collapsed ' +
|
||||
'element should be throttled');
|
||||
|
||||
await ensureElementRemoval(parent);
|
||||
}
|
||||
);
|
||||
|
||||
add_task_if_omta_enabled(
|
||||
async function no_restyling_for_compositor_animation_on_unrelated_style_change() {
|
||||
var div = addDiv(null);
|
||||
|
@ -10361,3 +10361,32 @@ nsLayoutUtils::ParseFontLanguageOverride(const nsAString& aLangTag)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ nscoord
|
||||
nsLayoutUtils::ResolveGapToLength(const nsStyleCoord& aCoord,
|
||||
nscoord aPercentageBasis)
|
||||
{
|
||||
switch (aCoord.GetUnit()) {
|
||||
case eStyleUnit_Normal:
|
||||
return nscoord(0);
|
||||
case eStyleUnit_Coord:
|
||||
return aCoord.GetCoordValue();
|
||||
case eStyleUnit_Percent:
|
||||
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
|
||||
return nscoord(0);
|
||||
}
|
||||
return NSToCoordFloorClamped(aPercentageBasis *
|
||||
aCoord.GetPercentValue());
|
||||
case eStyleUnit_Calc: {
|
||||
nsStyleCoord::Calc* calc = aCoord.GetCalcValue();
|
||||
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
|
||||
return std::max(nscoord(0), calc->mLength);
|
||||
}
|
||||
return std::max(nscoord(0), calc->mLength +
|
||||
NSToCoordFloorClamped(aPercentageBasis * calc->mPercent));
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected unit!");
|
||||
return nscoord(0);
|
||||
}
|
||||
}
|
||||
|
@ -3063,6 +3063,14 @@ public:
|
||||
|
||||
static uint32_t ParseFontLanguageOverride(const nsAString& aLangTag);
|
||||
|
||||
/**
|
||||
* Resolve a column-gap/row-gap to a definite size.
|
||||
* @note This method resolves 'normal' to zero.
|
||||
* Callers who want different behavior should handle 'normal' on their own.
|
||||
*/
|
||||
static nscoord ResolveGapToLength(const nsStyleCoord& aGap,
|
||||
nscoord aPercentageBasis);
|
||||
|
||||
private:
|
||||
static uint32_t sFontSizeInflationEmPerLine;
|
||||
static uint32_t sFontSizeInflationMinTwips;
|
||||
|
@ -289,18 +289,14 @@ nsColumnSetFrame::GetAvailableContentBSize(const ReflowInput& aReflowInput)
|
||||
|
||||
static nscoord
|
||||
GetColumnGap(nsColumnSetFrame* aFrame,
|
||||
const nsStyleColumn* aColStyle)
|
||||
const nsStyleColumn* aColStyle,
|
||||
nscoord aPercentageBasis)
|
||||
{
|
||||
if (eStyleUnit_Normal == aColStyle->mColumnGap.GetUnit())
|
||||
const auto& columnGap = aColStyle->mColumnGap;
|
||||
if (columnGap.GetUnit() == eStyleUnit_Normal) {
|
||||
return aFrame->StyleFont()->mFont.size;
|
||||
if (eStyleUnit_Coord == aColStyle->mColumnGap.GetUnit()) {
|
||||
nscoord colGap = aColStyle->mColumnGap.GetCoordValue();
|
||||
NS_ASSERTION(colGap >= 0, "negative column gap");
|
||||
return colGap;
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Unknown gap type");
|
||||
return 0;
|
||||
return nsLayoutUtils::ResolveGapToLength(columnGap, aPercentageBasis);
|
||||
}
|
||||
|
||||
nsColumnSetFrame::ReflowConfig
|
||||
@ -334,7 +330,7 @@ nsColumnSetFrame::ChooseColumnStrategy(const ReflowInput& aReflowInput,
|
||||
colBSize = std::min(colBSize, aReflowInput.ComputedMaxBSize());
|
||||
}
|
||||
|
||||
nscoord colGap = GetColumnGap(this, colStyle);
|
||||
nscoord colGap = GetColumnGap(this, colStyle, aReflowInput.ComputedISize());
|
||||
int32_t numColumns = colStyle->mColumnCount;
|
||||
|
||||
// If column-fill is set to 'balance', then we want to balance the columns.
|
||||
@ -518,7 +514,7 @@ nsColumnSetFrame::GetMinISize(gfxContext *aRenderingContext)
|
||||
// include n-1 column gaps.
|
||||
colISize = iSize;
|
||||
iSize *= colStyle->mColumnCount;
|
||||
nscoord colGap = GetColumnGap(this, colStyle);
|
||||
nscoord colGap = GetColumnGap(this, colStyle, NS_UNCONSTRAINEDSIZE);
|
||||
iSize += colGap * (colStyle->mColumnCount - 1);
|
||||
// The multiplication above can make 'width' negative (integer overflow),
|
||||
// so use std::max to protect against that.
|
||||
@ -539,7 +535,7 @@ nsColumnSetFrame::GetPrefISize(gfxContext *aRenderingContext)
|
||||
nscoord result = 0;
|
||||
DISPLAY_PREF_WIDTH(this, result);
|
||||
const nsStyleColumn* colStyle = StyleColumn();
|
||||
nscoord colGap = GetColumnGap(this, colStyle);
|
||||
nscoord colGap = GetColumnGap(this, colStyle, NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
nscoord colISize;
|
||||
if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsAbsoluteContainingBlock.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsFlexContainerFrame.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsRect.h"
|
||||
@ -846,8 +847,18 @@ nsContainerFrame::ComputeAutoSize(gfxContext* aRenderingContext,
|
||||
aBorder.ISize(aWM) - aPadding.ISize(aWM);
|
||||
// replaced elements always shrink-wrap
|
||||
if ((aFlags & ComputeSizeFlags::eShrinkWrap) || IsFrameOfType(eReplaced)) {
|
||||
// don't bother setting it if the result won't be used
|
||||
if (StylePosition()->ISize(aWM).GetUnit() == eStyleUnit_Auto) {
|
||||
// Only bother computing our 'auto' ISize if the result will be used.
|
||||
// It'll be used under two scenarios:
|
||||
// - If our ISize property is itself 'auto'.
|
||||
// - If we're using flex-basis in place of our ISize property (i.e. we're a
|
||||
// flex item with our inline axis being the main axis), AND we have
|
||||
// flex-basis:content.
|
||||
const nsStylePosition* pos = StylePosition();
|
||||
if (pos->ISize(aWM).GetUnit() == eStyleUnit_Auto ||
|
||||
(pos->mFlexBasis.GetUnit() == eStyleUnit_Enumerated &&
|
||||
pos->mFlexBasis.GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT &&
|
||||
IsFlexItem() &&
|
||||
nsFlexContainerFrame::IsItemInlineAxisMainAxis(this))) {
|
||||
result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased, aFlags);
|
||||
}
|
||||
} else {
|
||||
|
@ -5674,9 +5674,22 @@ nsFrame::ComputeSize(gfxContext* aRenderingContext,
|
||||
// nsFrame::ComputeSizeWithIntrinsicDimensions().
|
||||
const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
|
||||
if (flexBasis->GetUnit() != eStyleUnit_Auto) {
|
||||
// Override whichever styleCoord is in flex container's main axis:
|
||||
(flexMainAxis == eLogicalAxisInline ?
|
||||
inlineStyleCoord : blockStyleCoord) = flexBasis;
|
||||
// Replace our main-axis styleCoord pointer with a different one,
|
||||
// depending on our flex-basis value.
|
||||
auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
|
||||
? inlineStyleCoord : blockStyleCoord);
|
||||
if (flexBasis->GetUnit() == eStyleUnit_Enumerated &&
|
||||
flexBasis->GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT) {
|
||||
// We have 'flex-basis: content', which is equivalent to
|
||||
// 'flex-basis:auto; {main-size}: auto'. So, just swap in a dummy
|
||||
// 'auto' value to use for the main size property:
|
||||
static const nsStyleCoord autoStyleCoord(eStyleUnit_Auto);
|
||||
mainAxisCoord = &autoStyleCoord;
|
||||
} else {
|
||||
// For all other flex-basis values, we just swap in the flex-basis
|
||||
// itself for the main-size property here:
|
||||
mainAxisCoord = flexBasis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5916,9 +5929,23 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(gfxContext* aRenderingConte
|
||||
// inlineStyleCoord and blockStyleCoord in nsFrame::ComputeSize().
|
||||
const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
|
||||
if (flexBasis->GetUnit() != eStyleUnit_Auto) {
|
||||
// Override whichever styleCoord is in flex container's main axis:
|
||||
(flexMainAxis == eLogicalAxisInline ?
|
||||
inlineStyleCoord : blockStyleCoord) = flexBasis;
|
||||
// Replace our main-axis styleCoord pointer with a different one,
|
||||
// depending on our flex-basis value.
|
||||
auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
|
||||
? inlineStyleCoord : blockStyleCoord);
|
||||
|
||||
if (flexBasis->GetUnit() == eStyleUnit_Enumerated &&
|
||||
flexBasis->GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT) {
|
||||
// We have 'flex-basis: content', which is equivalent to
|
||||
// 'flex-basis:auto; {main-size}: auto'. So, just swap in a dummy
|
||||
// 'auto' value to use for the main size property:
|
||||
static const nsStyleCoord autoStyleCoord(eStyleUnit_Auto);
|
||||
mainAxisCoord = &autoStyleCoord;
|
||||
} else {
|
||||
// For all other flex-basis values, we just swap in the flex-basis
|
||||
// itself for the main-size property here:
|
||||
mainAxisCoord = flexBasis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11007,14 +11034,19 @@ IsFrameScrolledOutOfView(nsIFrame* aTarget,
|
||||
}
|
||||
|
||||
nsIFrame *scrollableParent = do_QueryFrame(scrollableFrame);
|
||||
nsRect scrollableRect =
|
||||
scrollableParent->GetVisualOverflowRectRelativeToSelf();
|
||||
// We consider that the target is scrolled out if the scrollable frame is
|
||||
// empty.
|
||||
if (scrollableRect.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRect transformedRect =
|
||||
nsLayoutUtils::TransformFrameRectToAncestor(aTarget,
|
||||
aTargetRect,
|
||||
scrollableParent);
|
||||
|
||||
nsRect scrollableRect =
|
||||
scrollableParent->GetVisualOverflowRectRelativeToSelf();
|
||||
if (transformedRect.IsEmpty()) {
|
||||
// If the transformed rect is empty it represents a line or a point that we
|
||||
// should check is outside the the scrollable rect.
|
||||
|
@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Reftest Reference</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
|
||||
<link rel="stylesheet" type="text/css" href="support/ahem.css">
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
border: 2px solid purple;
|
||||
padding: 2px;
|
||||
margin-bottom: 2em;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
flex-shrink: 0;
|
||||
min-width: 0;
|
||||
border: 2px solid teal;
|
||||
}
|
||||
|
||||
.smallText { font: 10px Ahem; }
|
||||
.bigText { font: 20px Ahem; }
|
||||
.spacerChild::before {
|
||||
content: '';
|
||||
display: block;
|
||||
background: brown;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
.justPadding {
|
||||
/* Empty div with 5px padding on each side */
|
||||
padding: 5px;
|
||||
background: cyan;
|
||||
}
|
||||
canvas { background: fuchsia }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Flex items have unspecified size properties: -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas width="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified main-size values, in testcase
|
||||
(removed here in reference case, because they shouldn't affect sizing): -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas width="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified cross-size values (should be honored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="height: 0px">a b</div>
|
||||
<div class="bigText" style="height: 40px">c</div>
|
||||
<div class="spacerChild" style="height: 20px"></div>
|
||||
<div class="justPadding" style="height: 10px"></div>
|
||||
<canvas width="20" style="height: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
CSS Test: Testing "flex-basis: content" in a row-oriented flex container
|
||||
</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
|
||||
<link rel="match" href="flexbox-flex-basis-content-001-ref.html">
|
||||
<link rel="stylesheet" type="text/css" href="support/ahem.css">
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
border: 2px solid purple;
|
||||
padding: 2px;
|
||||
margin-bottom: 2em;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
/* All flex items have "flex-basis: content" (and zero flex-shrink and
|
||||
min-main-size, to avoid any influence from those). */
|
||||
flex-basis: content;
|
||||
flex-shrink: 0;
|
||||
min-width: 0;
|
||||
border: 2px solid teal;
|
||||
}
|
||||
|
||||
.smallText { font: 10px Ahem; }
|
||||
.bigText { font: 20px Ahem; }
|
||||
.spacerChild::before {
|
||||
content: '';
|
||||
display: block;
|
||||
background: brown;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
.justPadding {
|
||||
/* Empty div with 5px padding on each side */
|
||||
padding: 5px;
|
||||
background: cyan;
|
||||
}
|
||||
canvas { background: fuchsia }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Flex items have unspecified size properties: -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas width="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified main-size values (should be ignored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="width: 0px">a b</div>
|
||||
<div class="bigText" style="width: 40px">c</div>
|
||||
<div class="spacerChild" style="width: 20px"></div>
|
||||
<div class="justPadding" style="width: 10px"></div>
|
||||
<canvas width="20" style="width: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified cross-size values (should be honored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="height: 0px">a b</div>
|
||||
<div class="bigText" style="height: 40px">c</div>
|
||||
<div class="spacerChild" style="height: 20px"></div>
|
||||
<div class="justPadding" style="height: 10px"></div>
|
||||
<canvas width="20" style="height: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
CSS Test: Testing "flex-basis: content" (set via the "flex" shorthand)
|
||||
in a row-oriented flex container.
|
||||
</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
|
||||
<link rel="match" href="flexbox-flex-basis-content-001-ref.html">
|
||||
<link rel="stylesheet" type="text/css" href="support/ahem.css">
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
border: 2px solid purple;
|
||||
padding: 2px;
|
||||
margin-bottom: 2em;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
/* All flex items have "flex-basis: content" (and zero flex-shrink and
|
||||
min-main-size, to avoid any influence from those). */
|
||||
flex: 0 0 content;
|
||||
min-width: 0;
|
||||
border: 2px solid teal;
|
||||
}
|
||||
|
||||
.smallText { font: 10px Ahem; }
|
||||
.bigText { font: 20px Ahem; }
|
||||
.spacerChild::before {
|
||||
content: '';
|
||||
display: block;
|
||||
background: brown;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
.justPadding {
|
||||
/* Empty div with 5px padding on each side */
|
||||
padding: 5px;
|
||||
background: cyan;
|
||||
}
|
||||
canvas { background: fuchsia }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Flex items have unspecified size properties: -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas width="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified main-size values (should be ignored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="width: 0px">a b</div>
|
||||
<div class="bigText" style="width: 40px">c</div>
|
||||
<div class="spacerChild" style="width: 20px"></div>
|
||||
<div class="justPadding" style="width: 10px"></div>
|
||||
<canvas width="20" style="width: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified cross-size values (should be honored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="height: 0px">a b</div>
|
||||
<div class="bigText" style="height: 40px">c</div>
|
||||
<div class="spacerChild" style="height: 20px"></div>
|
||||
<div class="justPadding" style="height: 10px"></div>
|
||||
<canvas width="20" style="height: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Reftest Reference</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
|
||||
<link rel="stylesheet" type="text/css" href="support/ahem.css">
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
border: 2px solid purple;
|
||||
padding: 2px;
|
||||
margin-right: 2em;
|
||||
width: 50px;
|
||||
height: 200px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
flex-shrink: 0;
|
||||
min-height: 0;
|
||||
border: 2px solid teal;
|
||||
}
|
||||
|
||||
.smallText { font: 10px Ahem; }
|
||||
.bigText { font: 20px Ahem; }
|
||||
.spacerChild::before {
|
||||
content: '';
|
||||
display: block;
|
||||
background: brown;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
.justPadding {
|
||||
/* Empty div with 5px padding on each side */
|
||||
padding: 5px;
|
||||
background: cyan;
|
||||
}
|
||||
canvas { background: fuchsia }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Flex items have unspecified size properties: -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas height="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified main-size values, in testcase
|
||||
(removed here in reference case, because they shouldn't affect sizing): -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas height="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified cross-size values (should be honored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="width: 0px">a b</div>
|
||||
<div class="bigText" style="width: 40px">c</div>
|
||||
<div class="spacerChild" style="width: 20px"></div>
|
||||
<div class="justPadding" style="width: 10px"></div>
|
||||
<canvas height="20" style="width: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
CSS Test: Testing "flex-basis: content" in a column-oriented flex container
|
||||
</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
|
||||
<link rel="match" href="flexbox-flex-basis-content-002-ref.html">
|
||||
<link rel="stylesheet" type="text/css" href="support/ahem.css">
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
border: 2px solid purple;
|
||||
padding: 2px;
|
||||
margin-right: 2em;
|
||||
width: 50px;
|
||||
height: 200px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
/* All flex items have "flex-basis: content" (and zero flex-shrink and
|
||||
min-main-size, to avoid any influence from those). */
|
||||
flex-basis: content;
|
||||
flex-shrink: 0;
|
||||
min-height: 0;
|
||||
border: 2px solid teal;
|
||||
}
|
||||
|
||||
.smallText { font: 10px Ahem; }
|
||||
.bigText { font: 20px Ahem; }
|
||||
.spacerChild::before {
|
||||
content: '';
|
||||
display: block;
|
||||
background: brown;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
.justPadding {
|
||||
/* Empty div with 5px padding on each side */
|
||||
padding: 5px;
|
||||
background: cyan;
|
||||
}
|
||||
canvas { background: fuchsia }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Flex items have unspecified size properties: -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas height="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified main-size values (should be ignored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="height: 0px">a b</div>
|
||||
<div class="bigText" style="height: 40px">c</div>
|
||||
<div class="spacerChild" style="height: 20px"></div>
|
||||
<div class="justPadding" style="height: 10px"></div>
|
||||
<canvas height="20" style="height: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified cross-size values (should be honored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="width: 0px">a b</div>
|
||||
<div class="bigText" style="width: 40px">c</div>
|
||||
<div class="spacerChild" style="width: 20px"></div>
|
||||
<div class="justPadding" style="width: 10px"></div>
|
||||
<canvas height="20" style="width: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
CSS Test: Testing "flex-basis: content" (set via the "flex" shorthand)
|
||||
in a column-oriented flex container.
|
||||
</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
|
||||
<link rel="match" href="flexbox-flex-basis-content-002-ref.html">
|
||||
<link rel="stylesheet" type="text/css" href="support/ahem.css">
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
border: 2px solid purple;
|
||||
padding: 2px;
|
||||
margin-right: 2em;
|
||||
width: 50px;
|
||||
height: 200px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
/* All flex items have "flex-basis: content" (and zero flex-shrink and
|
||||
min-main-size, to avoid any influence from those). */
|
||||
flex: 0 0 content;
|
||||
min-height: 0;
|
||||
border: 2px solid teal;
|
||||
}
|
||||
|
||||
.smallText { font: 10px Ahem; }
|
||||
.bigText { font: 20px Ahem; }
|
||||
.spacerChild::before {
|
||||
content: '';
|
||||
display: block;
|
||||
background: brown;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
.justPadding {
|
||||
/* Empty div with 5px padding on each side */
|
||||
padding: 5px;
|
||||
background: cyan;
|
||||
}
|
||||
canvas { background: fuchsia }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Flex items have unspecified size properties: -->
|
||||
<div class="container">
|
||||
<div class="smallText">a b</div>
|
||||
<div class="bigText">c</div>
|
||||
<div class="spacerChild"></div>
|
||||
<div class="justPadding"></div>
|
||||
<canvas height="20"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified main-size values (should be ignored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="height: 0px">a b</div>
|
||||
<div class="bigText" style="height: 40px">c</div>
|
||||
<div class="spacerChild" style="height: 20px"></div>
|
||||
<div class="justPadding" style="height: 10px"></div>
|
||||
<canvas height="20" style="height: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Various specified cross-size values (should be honored): -->
|
||||
<div class="container">
|
||||
<div class="smallText" style="width: 0px">a b</div>
|
||||
<div class="bigText" style="width: 40px">c</div>
|
||||
<div class="spacerChild" style="width: 20px"></div>
|
||||
<div class="justPadding" style="width: 10px"></div>
|
||||
<canvas height="20" style="width: 8px"></canvas>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -97,6 +97,12 @@ fuzzy-if(Android,158,32) == flexbox-align-self-vert-rtl-001.xhtml flexbox-align
|
||||
== flexbox-collapsed-item-horiz-002.html flexbox-collapsed-item-horiz-002-ref.html
|
||||
== flexbox-collapsed-item-horiz-003.html flexbox-collapsed-item-horiz-003-ref.html
|
||||
|
||||
# Tests for "flex-basis: content"
|
||||
== flexbox-flex-basis-content-001a.html flexbox-flex-basis-content-001-ref.html
|
||||
== flexbox-flex-basis-content-001b.html flexbox-flex-basis-content-001-ref.html
|
||||
== flexbox-flex-basis-content-002a.html flexbox-flex-basis-content-002-ref.html
|
||||
== flexbox-flex-basis-content-002b.html flexbox-flex-basis-content-002-ref.html
|
||||
|
||||
# Tests for flex-flow shorthand property
|
||||
== flexbox-flex-flow-001.html flexbox-flex-flow-001-ref.html
|
||||
== flexbox-flex-flow-002.html flexbox-flex-flow-002-ref.html
|
||||
|
@ -206,6 +206,7 @@ CSS_KEY(column, column)
|
||||
CSS_KEY(column-reverse, column_reverse)
|
||||
CSS_KEY(condensed, condensed)
|
||||
CSS_KEY(contain, contain)
|
||||
CSS_KEY(content, content)
|
||||
CSS_KEY(content-box, content_box)
|
||||
CSS_KEY(contents, contents)
|
||||
CSS_KEY(context-fill, context_fill)
|
||||
|
@ -1186,7 +1186,7 @@ CSS_PROP_COLUMN(
|
||||
ColumnGap,
|
||||
0,
|
||||
"",
|
||||
VARIANT_HL | VARIANT_NORMAL | VARIANT_CALC,
|
||||
VARIANT_HLP | VARIANT_NORMAL | VARIANT_CALC,
|
||||
nullptr,
|
||||
eStyleAnimType_Coord)
|
||||
CSS_PROP_SHORTHAND(
|
||||
@ -1406,7 +1406,7 @@ CSS_PROP_POSITION(
|
||||
// its own code to parse each subproperty. It does not depend on the
|
||||
// longhand parsing defined here.
|
||||
VARIANT_AHKLP | VARIANT_CALC,
|
||||
kWidthKTable,
|
||||
kFlexBasisKTable,
|
||||
eStyleAnimType_Coord)
|
||||
CSS_PROP_POSITION(
|
||||
flex-direction,
|
||||
|
@ -1914,6 +1914,20 @@ const KTableEntry nsCSSProps::kWidthKTable[] = {
|
||||
{ eCSSKeyword_UNKNOWN, -1 }
|
||||
};
|
||||
|
||||
// This must be the same as kWidthKTable, but just with 'content' added:
|
||||
const KTableEntry nsCSSProps::kFlexBasisKTable[] = {
|
||||
{ eCSSKeyword__moz_max_content, NS_STYLE_WIDTH_MAX_CONTENT },
|
||||
{ eCSSKeyword__moz_min_content, NS_STYLE_WIDTH_MIN_CONTENT },
|
||||
{ eCSSKeyword__moz_fit_content, NS_STYLE_WIDTH_FIT_CONTENT },
|
||||
{ eCSSKeyword__moz_available, NS_STYLE_WIDTH_AVAILABLE },
|
||||
{ eCSSKeyword_content, NS_STYLE_FLEX_BASIS_CONTENT },
|
||||
{ eCSSKeyword_UNKNOWN, -1 }
|
||||
};
|
||||
static_assert(ArrayLength(nsCSSProps::kFlexBasisKTable) ==
|
||||
ArrayLength(nsCSSProps::kWidthKTable) + 1,
|
||||
"kFlexBasisKTable should have the same entries as "
|
||||
"kWidthKTable, plus one more for 'content'");
|
||||
|
||||
const KTableEntry nsCSSProps::kWindowDraggingKTable[] = {
|
||||
{ eCSSKeyword_default, StyleWindowDragging::Default },
|
||||
{ eCSSKeyword_drag, StyleWindowDragging::Drag },
|
||||
|
@ -680,6 +680,7 @@ public:
|
||||
static const KTableEntry kVolumeKTable[];
|
||||
static const KTableEntry kWhitespaceKTable[];
|
||||
static const KTableEntry kWidthKTable[]; // also min-width, max-width
|
||||
static const KTableEntry kFlexBasisKTable[];
|
||||
static const KTableEntry kWindowDraggingKTable[];
|
||||
static const KTableEntry kWindowShadowKTable[];
|
||||
static const KTableEntry kWordBreakKTable[];
|
||||
|
@ -4777,7 +4777,7 @@ nsComputedDOMStyle::DoGetFlexBasis()
|
||||
// }
|
||||
|
||||
SetValueToCoord(val, StylePosition()->mFlexBasis, true,
|
||||
nullptr, nsCSSProps::kWidthKTable);
|
||||
nullptr, nsCSSProps::kFlexBasisKTable);
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
|
@ -676,6 +676,12 @@ enum class StyleGridTrackBreadth : uint8_t {
|
||||
#define NS_STYLE_WIDTH_MIN_CONTENT 1
|
||||
#define NS_STYLE_WIDTH_FIT_CONTENT 2
|
||||
#define NS_STYLE_WIDTH_AVAILABLE 3
|
||||
// The 'content' keyword is only valid for 'flex-basis' (not for 'width'). But
|
||||
// aside from that, the 'flex-basis' property accepts exactly the same values
|
||||
// as 'width'. So I'm listing this one 'flex-basis'-specific enumerated value
|
||||
// alongside the 'width' ones, to be sure we don't accidentally overload this
|
||||
// numeric value with two different meanings if new 'width' keywords are added.
|
||||
#define NS_STYLE_FLEX_BASIS_CONTENT 4
|
||||
|
||||
// See nsStyleDisplay.mPosition
|
||||
#define NS_STYLE_POSITION_STATIC 0
|
||||
|
@ -2911,7 +2911,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColumn
|
||||
|
||||
uint32_t mColumnCount; // [reset] see nsStyleConsts.h
|
||||
nsStyleCoord mColumnWidth; // [reset] coord, auto
|
||||
nsStyleCoord mColumnGap; // [reset] coord, normal
|
||||
nsStyleCoord mColumnGap; // [reset] <length-percentage> | normal
|
||||
|
||||
mozilla::StyleComplexColor mColumnRuleColor; // [reset]
|
||||
uint8_t mColumnRuleStyle; // [reset]
|
||||
|
@ -1710,7 +1710,7 @@ var gCSSProperties = {
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "normal" ],
|
||||
other_values: [ "2px", "1em", "4em",
|
||||
other_values: [ "2px", "1em", "4em", "3%", "calc(3%)", "calc(1em - 3%)",
|
||||
"calc(2px)",
|
||||
"calc(-2px)",
|
||||
"calc(0px)",
|
||||
@ -1721,7 +1721,7 @@ var gCSSProperties = {
|
||||
"calc(25px*3)",
|
||||
"calc(3*25px + 5em)",
|
||||
],
|
||||
invalid_values: [ "3%", "-1px", "4" ]
|
||||
invalid_values: [ "-3%", "-1px", "4" ]
|
||||
},
|
||||
"-moz-column-gap": {
|
||||
domProp: "MozColumnGap",
|
||||
@ -4741,6 +4741,7 @@ var gCSSProperties = {
|
||||
"calc(50px/(2 - 1))",
|
||||
],
|
||||
invalid_values: [ "none", "-2px",
|
||||
"content", /* (valid for 'flex-basis' but not 'width') */
|
||||
/* invalid calc() values */
|
||||
"calc(50%+ 2px)",
|
||||
"calc(50% +2px)",
|
||||
@ -5256,12 +5257,14 @@ var gCSSProperties = {
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ " auto" ],
|
||||
// NOTE: This is cribbed directly from the "width" chunk, since this
|
||||
// property takes the exact same values as width (albeit with
|
||||
// different semantics on 'auto').
|
||||
// NOTE: Besides "content", this is cribbed directly from the "width"
|
||||
// chunk, since this property takes the exact same values as width
|
||||
// (plus 'content' & with different semantics on 'auto').
|
||||
// XXXdholbert (Maybe these should get separated out into
|
||||
// a reusable array defined at the top of this file?)
|
||||
other_values: [ "15px", "3em", "15%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
|
||||
other_values: [
|
||||
"content",
|
||||
"15px", "3em", "15%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
|
||||
// valid calc() values
|
||||
"calc(-2px)",
|
||||
"calc(2px)",
|
||||
|
9
servo/Cargo.lock
generated
9
servo/Cargo.lock
generated
@ -1646,13 +1646,17 @@ dependencies = [
|
||||
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashglobe 0.1.0",
|
||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.19.0",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_bytes 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_arc 0.1.1",
|
||||
"smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_api 0.57.0 (git+https://github.com/servo/webrender)",
|
||||
@ -1888,6 +1892,8 @@ dependencies = [
|
||||
"ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"malloc_size_of_derive 0.0.1",
|
||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1898,6 +1904,8 @@ dependencies = [
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-websocket 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_allocator 0.0.1",
|
||||
"servo_arc 0.1.1",
|
||||
"servo_config 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1937,6 +1945,7 @@ dependencies = [
|
||||
"msg 0.0.1",
|
||||
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_arc 0.1.1",
|
||||
"servo_config 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -75,28 +75,16 @@ impl AxisSize {
|
||||
fn from_flex_basis(
|
||||
flex_basis: FlexBasis,
|
||||
main_length: LengthOrPercentageOrAuto,
|
||||
containing_length: Option<Au>
|
||||
containing_length: Au,
|
||||
) -> MaybeAuto {
|
||||
match (flex_basis, containing_length) {
|
||||
(GenericFlexBasis::Length(LengthOrPercentage::Length(length)), _) =>
|
||||
MaybeAuto::Specified(Au::from(length)),
|
||||
(GenericFlexBasis::Length(LengthOrPercentage::Percentage(percent)), Some(size)) =>
|
||||
MaybeAuto::Specified(size.scale_by(percent.0)),
|
||||
(GenericFlexBasis::Length(LengthOrPercentage::Percentage(_)), None) =>
|
||||
MaybeAuto::Auto,
|
||||
(GenericFlexBasis::Length(LengthOrPercentage::Calc(calc)), _) =>
|
||||
MaybeAuto::from_option(calc.to_used_value(containing_length)),
|
||||
(GenericFlexBasis::Content, _) =>
|
||||
MaybeAuto::Auto,
|
||||
(GenericFlexBasis::Auto, Some(size)) =>
|
||||
MaybeAuto::from_style(main_length, size),
|
||||
(GenericFlexBasis::Auto, None) => {
|
||||
if let LengthOrPercentageOrAuto::Length(length) = main_length {
|
||||
MaybeAuto::Specified(Au::from(length))
|
||||
} else {
|
||||
MaybeAuto::Auto
|
||||
}
|
||||
}
|
||||
let width = match flex_basis {
|
||||
GenericFlexBasis::Content => return MaybeAuto::Auto,
|
||||
GenericFlexBasis::Width(width) => width,
|
||||
};
|
||||
|
||||
match width.0 {
|
||||
LengthOrPercentageOrAuto::Auto => MaybeAuto::from_style(main_length, containing_length),
|
||||
other => MaybeAuto::from_style(other, containing_length),
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +149,7 @@ impl FlexItem {
|
||||
Direction::Inline => {
|
||||
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis,
|
||||
block.fragment.style.content_inline_size(),
|
||||
Some(containing_length));
|
||||
containing_length);
|
||||
|
||||
// These methods compute auto margins to zero length, which is exactly what we want.
|
||||
block.fragment.compute_border_and_padding(containing_length);
|
||||
@ -183,7 +171,7 @@ impl FlexItem {
|
||||
Direction::Block => {
|
||||
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis,
|
||||
block.fragment.style.content_block_size(),
|
||||
Some(containing_length));
|
||||
containing_length);
|
||||
let content_size = block.fragment.border_box.size.block
|
||||
- block.fragment.border_padding.block_start_end()
|
||||
+ block.fragment.box_sizing_boundary(direction);
|
||||
|
@ -106,6 +106,7 @@ impl Flow for MulticolFlow {
|
||||
{
|
||||
let column_style = self.block_flow.fragment.style.get_column();
|
||||
|
||||
// FIXME(#20498): This should support percentages too.
|
||||
let column_gap = match column_style.column_gap {
|
||||
Either::First(len) => len.into(),
|
||||
Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size.size(),
|
||||
|
@ -23,13 +23,17 @@ app_units = "0.6"
|
||||
cssparser = "0.23.0"
|
||||
euclid = "0.17"
|
||||
hashglobe = { path = "../hashglobe" }
|
||||
hyper = "0.10"
|
||||
hyper_serde = "0.8"
|
||||
mozjs = { version = "0.6", features = ["promises"], optional = true }
|
||||
selectors = { path = "../selectors" }
|
||||
serde = "1.0.27"
|
||||
serde_bytes = { version = "0.10", optional = true }
|
||||
servo_arc = { path = "../servo_arc" }
|
||||
smallbitvec = "1.0.3"
|
||||
smallvec = "0.6"
|
||||
string_cache = { version = "0.7", optional = true }
|
||||
time = "0.1.17"
|
||||
url = { version = "1.2", optional = true }
|
||||
webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true }
|
||||
xml5ever = { version = "0.12", optional = true }
|
||||
|
@ -47,9 +47,12 @@ extern crate app_units;
|
||||
extern crate cssparser;
|
||||
extern crate euclid;
|
||||
extern crate hashglobe;
|
||||
extern crate hyper;
|
||||
extern crate hyper_serde;
|
||||
#[cfg(feature = "servo")]
|
||||
extern crate mozjs as js;
|
||||
extern crate selectors;
|
||||
extern crate serde;
|
||||
#[cfg(feature = "servo")]
|
||||
extern crate serde_bytes;
|
||||
extern crate servo_arc;
|
||||
@ -57,6 +60,7 @@ extern crate smallbitvec;
|
||||
extern crate smallvec;
|
||||
#[cfg(feature = "servo")]
|
||||
extern crate string_cache;
|
||||
extern crate time;
|
||||
#[cfg(feature = "url")]
|
||||
extern crate url;
|
||||
extern crate void;
|
||||
@ -69,6 +73,7 @@ extern crate xml5ever;
|
||||
use serde_bytes::ByteBuf;
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
use std::mem::size_of;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ops::Range;
|
||||
use std::os::raw::c_void;
|
||||
use void::Void;
|
||||
@ -591,6 +596,18 @@ impl<T: MallocSizeOf> MallocConditionalSizeOf for servo_arc::Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// If a mutex is stored directly as a member of a data type that is being measured,
|
||||
/// it is the unique owner of its contents and deserves to be measured.
|
||||
///
|
||||
/// If a mutex is stored inside of an Arc value as a member of a data type that is being measured,
|
||||
/// the Arc will not be automatically measured so there is no risk of overcounting the mutex's
|
||||
/// contents.
|
||||
impl<T: MallocSizeOf> MallocSizeOf for std::sync::Mutex<T> {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
(*self.lock().unwrap()).size_of(ops)
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for smallbitvec::SmallBitVec {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
if let Some(ptr) = self.heap_ptr() {
|
||||
@ -802,3 +819,90 @@ impl MallocSizeOf for xml5ever::QualName {
|
||||
self.local.size_of(ops)
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for hyper::header::Headers {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
self.iter().fold(0, |acc, x| {
|
||||
let name = x.name();
|
||||
let raw = self.get_raw(name);
|
||||
acc + raw.size_of(ops)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for hyper::header::ContentType {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
self.0.size_of(ops)
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for hyper::mime::Mime {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
self.0.size_of(ops) +
|
||||
self.1.size_of(ops) +
|
||||
self.2.size_of(ops)
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for hyper::mime::Attr {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
match *self {
|
||||
hyper::mime::Attr::Ext(ref s) => s.size_of(ops),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for hyper::mime::Value {
|
||||
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
||||
self.len() // Length of string value in bytes (not the char length of a string)!
|
||||
}
|
||||
}
|
||||
|
||||
malloc_size_of_is_0!(time::Duration);
|
||||
malloc_size_of_is_0!(time::Tm);
|
||||
|
||||
impl<T> MallocSizeOf for hyper_serde::Serde<T> where
|
||||
for <'de> hyper_serde::De<T>: serde::Deserialize<'de>,
|
||||
for <'a> hyper_serde::Ser<'a, T>: serde::Serialize,
|
||||
T: MallocSizeOf {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
self.0.size_of(ops)
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholder for unique case where internals of Sender cannot be measured.
|
||||
// malloc size of is 0 macro complains about type supplied!
|
||||
impl<T> MallocSizeOf for std::sync::mpsc::Sender<T> {
|
||||
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for hyper::status::StatusCode {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
match *self {
|
||||
hyper::status::StatusCode::Unregistered(u) => u.size_of(ops),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Measurable that defers to inner value and used to verify MallocSizeOf implementation in a
|
||||
/// struct.
|
||||
#[derive(Clone)]
|
||||
pub struct Measurable<T: MallocSizeOf> (pub T);
|
||||
|
||||
impl<T: MallocSizeOf> Deref for Measurable<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MallocSizeOf> DerefMut for Measurable<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ immeta = "0.3.6"
|
||||
ipc-channel = "0.10"
|
||||
lazy_static = "1"
|
||||
log = "0.4"
|
||||
malloc_size_of = { path = "../malloc_size_of" }
|
||||
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
||||
matches = "0.1"
|
||||
mime = "0.2.1"
|
||||
mime_guess = "1.8.0"
|
||||
@ -33,6 +35,8 @@ openssl = "0.9"
|
||||
profile_traits = {path = "../profile_traits"}
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
servo_allocator = {path = "../allocator"}
|
||||
servo_arc = {path = "../servo_arc"}
|
||||
servo_config = {path = "../config"}
|
||||
servo_url = {path = "../url"}
|
||||
servo-websocket = { version = "0.21", default-features = false, features = ["sync"] }
|
||||
|
@ -14,14 +14,17 @@ use hyper::header::Headers;
|
||||
use hyper::method::Method;
|
||||
use hyper::status::StatusCode;
|
||||
use hyper_serde::Serde;
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf, MallocUnconditionalShallowSizeOf};
|
||||
use malloc_size_of::Measurable;
|
||||
use net_traits::{Metadata, FetchMetadata};
|
||||
use net_traits::request::Request;
|
||||
use net_traits::response::{HttpsState, Response, ResponseBody};
|
||||
use servo_arc::Arc;
|
||||
use servo_config::prefs::PREFS;
|
||||
use servo_url::ServoUrl;
|
||||
use std::collections::HashMap;
|
||||
use std::str;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Mutex;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use time;
|
||||
@ -29,7 +32,7 @@ use time::{Duration, Tm};
|
||||
|
||||
|
||||
/// The key used to differentiate requests in the cache.
|
||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Eq, Hash, MallocSizeOf, PartialEq )]
|
||||
pub struct CacheKey {
|
||||
url: ServoUrl
|
||||
}
|
||||
@ -56,9 +59,16 @@ impl CacheKey {
|
||||
/// A complete cached resource.
|
||||
#[derive(Clone)]
|
||||
struct CachedResource {
|
||||
metadata: CachedMetadata,
|
||||
request_headers: Arc<Mutex<Headers>>,
|
||||
body: Arc<Mutex<ResponseBody>>,
|
||||
aborted: Arc<AtomicBool>,
|
||||
awaiting_body: Arc<Mutex<Vec<Sender<Data>>>>,
|
||||
data: Measurable<MeasurableCachedResource>
|
||||
}
|
||||
|
||||
#[derive(Clone, MallocSizeOf)]
|
||||
struct MeasurableCachedResource {
|
||||
metadata: CachedMetadata,
|
||||
location_url: Option<Result<ServoUrl, String>>,
|
||||
https_state: HttpsState,
|
||||
status: Option<StatusCode>,
|
||||
@ -66,25 +76,47 @@ struct CachedResource {
|
||||
url_list: Vec<ServoUrl>,
|
||||
expires: Duration,
|
||||
last_validated: Tm,
|
||||
aborted: Arc<AtomicBool>,
|
||||
awaiting_body: Arc<Mutex<Vec<Sender<Data>>>>
|
||||
}
|
||||
|
||||
impl MallocSizeOf for CachedResource {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
self.request_headers.unconditional_size_of(ops) +
|
||||
self.body.unconditional_size_of(ops) +
|
||||
self.aborted.unconditional_size_of(ops) +
|
||||
self.awaiting_body.unconditional_size_of(ops) +
|
||||
self.data.size_of(ops)
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
|
||||
#[derive(Clone)]
|
||||
struct CachedMetadata {
|
||||
/// Headers
|
||||
pub headers: Arc<Mutex<Headers>>,
|
||||
/// Fields that implement MallocSizeOf
|
||||
pub data: Measurable<MeasurableCachedMetadata>
|
||||
}
|
||||
|
||||
#[derive(Clone, MallocSizeOf)]
|
||||
struct MeasurableCachedMetadata {
|
||||
/// Final URL after redirects.
|
||||
pub final_url: ServoUrl,
|
||||
/// MIME type / subtype.
|
||||
pub content_type: Option<Serde<ContentType>>,
|
||||
/// Character set.
|
||||
pub charset: Option<String>,
|
||||
/// Headers
|
||||
pub headers: Arc<Mutex<Headers>>,
|
||||
/// HTTP Status
|
||||
pub status: Option<(u16, Vec<u8>)>
|
||||
}
|
||||
|
||||
impl MallocSizeOf for CachedMetadata {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
self.headers.unconditional_shallow_size_of(ops) +
|
||||
self.headers.size_of(ops) +
|
||||
self.data.size_of(ops)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around a cached response, including information on re-validation needs
|
||||
pub struct CachedResponse {
|
||||
/// The response constructed from the cached resource
|
||||
@ -94,6 +126,7 @@ pub struct CachedResponse {
|
||||
}
|
||||
|
||||
/// A memory cache.
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct HttpCache {
|
||||
/// cached responses.
|
||||
entries: HashMap<CacheKey, Vec<CachedResource>>,
|
||||
@ -278,7 +311,7 @@ fn create_cached_response(request: &Request,
|
||||
cached_headers: &Headers,
|
||||
done_chan: &mut DoneChannel)
|
||||
-> CachedResponse {
|
||||
let mut response = Response::new(cached_resource.metadata.final_url.clone());
|
||||
let mut response = Response::new(cached_resource.data.metadata.data.final_url.clone());
|
||||
response.headers = cached_headers.clone();
|
||||
response.body = cached_resource.body.clone();
|
||||
if let ResponseBody::Receiving(_) = *cached_resource.body.lock().unwrap() {
|
||||
@ -286,18 +319,18 @@ fn create_cached_response(request: &Request,
|
||||
*done_chan = Some((done_sender.clone(), done_receiver));
|
||||
cached_resource.awaiting_body.lock().unwrap().push(done_sender);
|
||||
}
|
||||
response.location_url = cached_resource.location_url.clone();
|
||||
response.status = cached_resource.status.clone();
|
||||
response.raw_status = cached_resource.raw_status.clone();
|
||||
response.url_list = cached_resource.url_list.clone();
|
||||
response.https_state = cached_resource.https_state.clone();
|
||||
response.location_url = cached_resource.data.location_url.clone();
|
||||
response.status = cached_resource.data.status.clone();
|
||||
response.raw_status = cached_resource.data.raw_status.clone();
|
||||
response.url_list = cached_resource.data.url_list.clone();
|
||||
response.https_state = cached_resource.data.https_state.clone();
|
||||
response.referrer = request.referrer.to_url().cloned();
|
||||
response.referrer_policy = request.referrer_policy.clone();
|
||||
response.aborted = cached_resource.aborted.clone();
|
||||
let expires = cached_resource.expires;
|
||||
let expires = cached_resource.data.expires;
|
||||
let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires);
|
||||
let now = Duration::seconds(time::now().to_timespec().sec);
|
||||
let last_validated = Duration::seconds(cached_resource.last_validated.to_timespec().sec);
|
||||
let last_validated = Duration::seconds(cached_resource.data.last_validated.to_timespec().sec);
|
||||
let time_since_validated = now - last_validated;
|
||||
// TODO: take must-revalidate into account <https://tools.ietf.org/html/rfc7234#section-5.2.2.1>
|
||||
// TODO: if this cache is to be considered shared, take proxy-revalidate into account
|
||||
@ -312,18 +345,20 @@ fn create_cached_response(request: &Request,
|
||||
fn create_resource_with_bytes_from_resource(bytes: &[u8], resource: &CachedResource)
|
||||
-> CachedResource {
|
||||
CachedResource {
|
||||
metadata: resource.metadata.clone(),
|
||||
request_headers: resource.request_headers.clone(),
|
||||
body: Arc::new(Mutex::new(ResponseBody::Done(bytes.to_owned()))),
|
||||
location_url: resource.location_url.clone(),
|
||||
https_state: resource.https_state.clone(),
|
||||
status: Some(StatusCode::PartialContent),
|
||||
raw_status: Some((206, b"Partial Content".to_vec())),
|
||||
url_list: resource.url_list.clone(),
|
||||
expires: resource.expires.clone(),
|
||||
last_validated: resource.last_validated.clone(),
|
||||
aborted: Arc::new(AtomicBool::new(false)),
|
||||
awaiting_body: Arc::new(Mutex::new(vec![]))
|
||||
awaiting_body: Arc::new(Mutex::new(vec![])),
|
||||
data: Measurable(MeasurableCachedResource {
|
||||
metadata: resource.data.metadata.clone(),
|
||||
location_url: resource.data.location_url.clone(),
|
||||
https_state: resource.data.https_state.clone(),
|
||||
status: Some(StatusCode::PartialContent),
|
||||
raw_status: Some((206, b"Partial Content".to_vec())),
|
||||
url_list: resource.data.url_list.clone(),
|
||||
expires: resource.data.expires.clone(),
|
||||
last_validated: resource.data.last_validated.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,13 +369,13 @@ fn handle_range_request(request: &Request,
|
||||
done_chan: &mut DoneChannel)
|
||||
-> Option<CachedResponse> {
|
||||
let mut complete_cached_resources = candidates.iter().filter(|resource| {
|
||||
match resource.raw_status {
|
||||
match resource.data.raw_status {
|
||||
Some((ref code, _)) => *code == 200,
|
||||
None => false
|
||||
}
|
||||
});
|
||||
let partial_cached_resources = candidates.iter().filter(|resource| {
|
||||
match resource.raw_status {
|
||||
match resource.data.raw_status {
|
||||
Some((ref code, _)) => *code == 206,
|
||||
None => false
|
||||
}
|
||||
@ -361,7 +396,7 @@ fn handle_range_request(request: &Request,
|
||||
let requested = body.get(b..e);
|
||||
if let Some(bytes) = requested {
|
||||
let new_resource = create_resource_with_bytes_from_resource(bytes, complete_resource);
|
||||
let cached_headers = new_resource.metadata.headers.lock().unwrap();
|
||||
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
||||
let cached_response = create_cached_response(request, &new_resource, &*cached_headers, done_chan);
|
||||
return Some(cached_response);
|
||||
}
|
||||
@ -369,7 +404,7 @@ fn handle_range_request(request: &Request,
|
||||
},
|
||||
(&header::ByteRangeSpec::FromTo(beginning, end), None) => {
|
||||
for partial_resource in partial_cached_resources {
|
||||
let headers = partial_resource.metadata.headers.lock().unwrap();
|
||||
let headers = partial_resource.data.metadata.headers.lock().unwrap();
|
||||
let content_range = headers.get::<header::ContentRange>();
|
||||
let (res_beginning, res_end) = match content_range {
|
||||
Some(&header::ContentRange(
|
||||
@ -401,7 +436,7 @@ fn handle_range_request(request: &Request,
|
||||
let requested = body.get(b..);
|
||||
if let Some(bytes) = requested {
|
||||
let new_resource = create_resource_with_bytes_from_resource(bytes, complete_resource);
|
||||
let cached_headers = new_resource.metadata.headers.lock().unwrap();
|
||||
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
||||
let cached_response = create_cached_response(request, &new_resource, &*cached_headers, done_chan);
|
||||
return Some(cached_response);
|
||||
}
|
||||
@ -409,7 +444,7 @@ fn handle_range_request(request: &Request,
|
||||
},
|
||||
(&header::ByteRangeSpec::AllFrom(beginning), None) => {
|
||||
for partial_resource in partial_cached_resources {
|
||||
let headers = partial_resource.metadata.headers.lock().unwrap();
|
||||
let headers = partial_resource.data.metadata.headers.lock().unwrap();
|
||||
let content_range = headers.get::<header::ContentRange>();
|
||||
let (res_beginning, res_end, total) = match content_range {
|
||||
Some(&header::ContentRange(
|
||||
@ -441,7 +476,7 @@ fn handle_range_request(request: &Request,
|
||||
let requested = body.get(from_byte..);
|
||||
if let Some(bytes) = requested {
|
||||
let new_resource = create_resource_with_bytes_from_resource(bytes, complete_resource);
|
||||
let cached_headers = new_resource.metadata.headers.lock().unwrap();
|
||||
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
||||
let cached_response = create_cached_response(request, &new_resource, &*cached_headers, done_chan);
|
||||
return Some(cached_response);
|
||||
}
|
||||
@ -449,7 +484,7 @@ fn handle_range_request(request: &Request,
|
||||
},
|
||||
(&header::ByteRangeSpec::Last(offset), None) => {
|
||||
for partial_resource in partial_cached_resources {
|
||||
let headers = partial_resource.metadata.headers.lock().unwrap();
|
||||
let headers = partial_resource.data.metadata.headers.lock().unwrap();
|
||||
let content_range = headers.get::<header::ContentRange>();
|
||||
let (res_beginning, res_end, total) = match content_range {
|
||||
Some(&header::ContentRange(
|
||||
@ -501,7 +536,7 @@ impl HttpCache {
|
||||
let mut candidates = vec![];
|
||||
for cached_resource in resources {
|
||||
let mut can_be_constructed = true;
|
||||
let cached_headers = cached_resource.metadata.headers.lock().unwrap();
|
||||
let cached_headers = cached_resource.data.metadata.headers.lock().unwrap();
|
||||
let original_request_headers = cached_resource.request_headers.lock().unwrap();
|
||||
if let Some(vary_data) = cached_headers.get_raw("Vary") {
|
||||
// Calculating Secondary Keys with Vary <https://tools.ietf.org/html/rfc7234#section-4.1>
|
||||
@ -554,7 +589,7 @@ impl HttpCache {
|
||||
// Returning the first response that can be constructed
|
||||
// TODO: select the most appropriate one, using a known mechanism from a selecting header field,
|
||||
// or using the Date header to return the most recent one.
|
||||
let cached_headers = cached_resource.metadata.headers.lock().unwrap();
|
||||
let cached_headers = cached_resource.data.metadata.headers.lock().unwrap();
|
||||
let cached_response = create_cached_response(request, cached_resource, &*cached_headers, done_chan);
|
||||
return Some(cached_response);
|
||||
}
|
||||
@ -589,24 +624,24 @@ impl HttpCache {
|
||||
let entry_key = CacheKey::new(request.clone());
|
||||
if let Some(cached_resources) = self.entries.get_mut(&entry_key) {
|
||||
for cached_resource in cached_resources.iter_mut() {
|
||||
let mut stored_headers = cached_resource.metadata.headers.lock().unwrap();
|
||||
// Received a response with 304 status code, in response to a request that matches a cached resource.
|
||||
// 1. update the headers of the cached resource.
|
||||
// 2. return a response, constructed from the cached resource.
|
||||
stored_headers.extend(response.headers.iter());
|
||||
let mut constructed_response = Response::new(cached_resource.metadata.final_url.clone());
|
||||
constructed_response.headers = stored_headers.clone();
|
||||
let mut constructed_response = Response::new(cached_resource.data.metadata.data.final_url.clone());
|
||||
constructed_response.body = cached_resource.body.clone();
|
||||
constructed_response.status = cached_resource.status.clone();
|
||||
constructed_response.https_state = cached_resource.https_state.clone();
|
||||
constructed_response.status = cached_resource.data.status.clone();
|
||||
constructed_response.https_state = cached_resource.data.https_state.clone();
|
||||
constructed_response.referrer = request.referrer.to_url().cloned();
|
||||
constructed_response.referrer_policy = request.referrer_policy.clone();
|
||||
constructed_response.raw_status = cached_resource.raw_status.clone();
|
||||
constructed_response.url_list = cached_resource.url_list.clone();
|
||||
constructed_response.raw_status = cached_resource.data.raw_status.clone();
|
||||
constructed_response.url_list = cached_resource.data.url_list.clone();
|
||||
// done_chan will have been set to Some by http_network_fetch,
|
||||
// set it back to None since the response returned here replaces the 304 one from the network.
|
||||
*done_chan = None;
|
||||
cached_resource.expires = get_response_expiry(&constructed_response);
|
||||
cached_resource.data.expires = get_response_expiry(&constructed_response);
|
||||
let mut stored_headers = cached_resource.data.metadata.headers.lock().unwrap();
|
||||
stored_headers.extend(response.headers.iter());
|
||||
constructed_response.headers = stored_headers.clone();
|
||||
return Some(constructed_response);
|
||||
}
|
||||
}
|
||||
@ -617,7 +652,7 @@ impl HttpCache {
|
||||
let entry_key = CacheKey::from_servo_url(url);
|
||||
if let Some(cached_resources) = self.entries.get_mut(&entry_key) {
|
||||
for cached_resource in cached_resources.iter_mut() {
|
||||
cached_resource.expires = Duration::seconds(0i64);
|
||||
cached_resource.data.expires = Duration::seconds(0i64);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -664,25 +699,29 @@ impl HttpCache {
|
||||
}
|
||||
let expiry = get_response_expiry(&response);
|
||||
let cacheable_metadata = CachedMetadata {
|
||||
final_url: metadata.final_url,
|
||||
content_type: metadata.content_type,
|
||||
charset: metadata.charset,
|
||||
status: metadata.status,
|
||||
headers: Arc::new(Mutex::new(response.headers.clone()))
|
||||
headers: Arc::new(Mutex::new(response.headers.clone())),
|
||||
data: Measurable(MeasurableCachedMetadata {
|
||||
final_url: metadata.final_url,
|
||||
content_type: metadata.content_type,
|
||||
charset: metadata.charset,
|
||||
status: metadata.status
|
||||
})
|
||||
};
|
||||
let entry_resource = CachedResource {
|
||||
metadata: cacheable_metadata,
|
||||
request_headers: Arc::new(Mutex::new(request.headers.clone())),
|
||||
body: response.body.clone(),
|
||||
location_url: response.location_url.clone(),
|
||||
https_state: response.https_state.clone(),
|
||||
status: response.status.clone(),
|
||||
raw_status: response.raw_status.clone(),
|
||||
url_list: response.url_list.clone(),
|
||||
expires: expiry,
|
||||
last_validated: time::now(),
|
||||
aborted: response.aborted.clone(),
|
||||
awaiting_body: Arc::new(Mutex::new(vec![]))
|
||||
awaiting_body: Arc::new(Mutex::new(vec![])),
|
||||
data: Measurable(MeasurableCachedResource {
|
||||
metadata: cacheable_metadata,
|
||||
location_url: response.location_url.clone(),
|
||||
https_state: response.https_state.clone(),
|
||||
status: response.status.clone(),
|
||||
raw_status: response.raw_status.clone(),
|
||||
url_list: response.url_list.clone(),
|
||||
expires: expiry,
|
||||
last_validated: time::now()
|
||||
})
|
||||
};
|
||||
let entry = self.entries.entry(entry_key).or_insert(vec![]);
|
||||
entry.push(entry_resource);
|
||||
|
@ -17,6 +17,8 @@ extern crate ipc_channel;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use] extern crate log;
|
||||
extern crate malloc_size_of;
|
||||
#[macro_use] extern crate malloc_size_of_derive;
|
||||
#[macro_use] #[no_link] extern crate matches;
|
||||
#[macro_use]
|
||||
extern crate mime;
|
||||
@ -24,9 +26,12 @@ extern crate mime_guess;
|
||||
extern crate msg;
|
||||
extern crate net_traits;
|
||||
extern crate openssl;
|
||||
#[macro_use]
|
||||
extern crate profile_traits;
|
||||
#[macro_use] extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate servo_allocator;
|
||||
extern crate servo_arc;
|
||||
extern crate servo_config;
|
||||
extern crate servo_url;
|
||||
extern crate time;
|
||||
|
@ -16,6 +16,7 @@ use http_cache::HttpCache;
|
||||
use http_loader::{HttpState, http_redirect_fetch};
|
||||
use hyper_serde::Serde;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcReceiverSet, IpcSender};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use net_traits::{CookieSource, CoreResourceThread};
|
||||
use net_traits::{CoreResourceMsg, CustomResponseMediator, FetchChannels};
|
||||
use net_traits::{FetchResponseMsg, ResourceThreads, WebSocketDomAction};
|
||||
@ -23,9 +24,12 @@ use net_traits::WebSocketNetworkEvent;
|
||||
use net_traits::request::{Request, RequestInit};
|
||||
use net_traits::response::{Response, ResponseInit};
|
||||
use net_traits::storage_thread::StorageThreadMsg;
|
||||
use profile_traits::mem::{Report, ReportsChan, ReportKind};
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::time::ProfilerChan;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
use servo_allocator;
|
||||
use servo_config::opts;
|
||||
use servo_config::resource_files::resources_dir_path;
|
||||
use servo_url::ServoUrl;
|
||||
@ -47,13 +51,15 @@ const TFD_PROVIDER: &'static TFDProvider = &TFDProvider;
|
||||
/// Returns a tuple of (public, private) senders to the new threads.
|
||||
pub fn new_resource_threads(user_agent: Cow<'static, str>,
|
||||
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
profiler_chan: ProfilerChan,
|
||||
time_profiler_chan: ProfilerChan,
|
||||
mem_profiler_chan: MemProfilerChan,
|
||||
config_dir: Option<PathBuf>)
|
||||
-> (ResourceThreads, ResourceThreads) {
|
||||
let (public_core, private_core) = new_core_resource_thread(
|
||||
user_agent,
|
||||
devtools_chan,
|
||||
profiler_chan,
|
||||
time_profiler_chan,
|
||||
mem_profiler_chan,
|
||||
config_dir.clone());
|
||||
let storage: IpcSender<StorageThreadMsg> = StorageThreadFactory::new(config_dir);
|
||||
(ResourceThreads::new(public_core, storage.clone()),
|
||||
@ -64,22 +70,34 @@ pub fn new_resource_threads(user_agent: Cow<'static, str>,
|
||||
/// Create a CoreResourceThread
|
||||
pub fn new_core_resource_thread(user_agent: Cow<'static, str>,
|
||||
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
profiler_chan: ProfilerChan,
|
||||
time_profiler_chan: ProfilerChan,
|
||||
mem_profiler_chan: MemProfilerChan,
|
||||
config_dir: Option<PathBuf>)
|
||||
-> (CoreResourceThread, CoreResourceThread) {
|
||||
let (public_setup_chan, public_setup_port) = ipc::channel().unwrap();
|
||||
let (private_setup_chan, private_setup_port) = ipc::channel().unwrap();
|
||||
let (report_chan, report_port) = ipc::channel().unwrap();
|
||||
|
||||
thread::Builder::new().name("ResourceManager".to_owned()).spawn(move || {
|
||||
let resource_manager = CoreResourceManager::new(
|
||||
user_agent, devtools_chan, profiler_chan
|
||||
user_agent, devtools_chan, time_profiler_chan
|
||||
);
|
||||
|
||||
let mut channel_manager = ResourceChannelManager {
|
||||
resource_manager: resource_manager,
|
||||
config_dir: config_dir,
|
||||
};
|
||||
channel_manager.start(public_setup_port,
|
||||
private_setup_port);
|
||||
|
||||
mem_profiler_chan.run_with_memory_reporting(|| (
|
||||
channel_manager.start(
|
||||
public_setup_port,
|
||||
private_setup_port,
|
||||
report_port)
|
||||
),
|
||||
String::from("network-cache-reporter"),
|
||||
report_chan,
|
||||
|report_chan| report_chan);
|
||||
|
||||
}).expect("Thread spawning failed");
|
||||
(public_setup_chan, private_setup_chan)
|
||||
}
|
||||
@ -127,31 +145,69 @@ impl ResourceChannelManager {
|
||||
#[allow(unsafe_code)]
|
||||
fn start(&mut self,
|
||||
public_receiver: IpcReceiver<CoreResourceMsg>,
|
||||
private_receiver: IpcReceiver<CoreResourceMsg>) {
|
||||
private_receiver: IpcReceiver<CoreResourceMsg>,
|
||||
memory_reporter: IpcReceiver<ReportsChan>) {
|
||||
let (public_http_state, private_http_state) =
|
||||
create_http_states(self.config_dir.as_ref().map(Deref::deref));
|
||||
|
||||
let mut rx_set = IpcReceiverSet::new().unwrap();
|
||||
let private_id = rx_set.add(private_receiver).unwrap();
|
||||
let public_id = rx_set.add(public_receiver).unwrap();
|
||||
let reporter_id = rx_set.add(memory_reporter).unwrap();
|
||||
|
||||
loop {
|
||||
for (id, data) in rx_set.select().unwrap().into_iter().map(|m| m.unwrap()) {
|
||||
let group = if id == private_id {
|
||||
&private_http_state
|
||||
for receiver in rx_set.select().unwrap().into_iter() {
|
||||
// Handles case where profiler thread shuts down before resource thread.
|
||||
match receiver {
|
||||
ipc::IpcSelectionResult::ChannelClosed(..) => continue,
|
||||
_ => {}
|
||||
}
|
||||
let (id, data) = receiver.unwrap();
|
||||
// If message is memory report, get the size_of of public and private http caches
|
||||
if id == reporter_id {
|
||||
if let Ok(msg) = data.to() {
|
||||
self.process_report(msg, &private_http_state, &public_http_state);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
assert_eq!(id, public_id);
|
||||
&public_http_state
|
||||
};
|
||||
if let Ok(msg) = data.to() {
|
||||
if !self.process_msg(msg, group) {
|
||||
return;
|
||||
let group = if id == private_id {
|
||||
&private_http_state
|
||||
} else {
|
||||
assert_eq!(id, public_id);
|
||||
&public_http_state
|
||||
};
|
||||
if let Ok(msg) = data.to() {
|
||||
if !self.process_msg(msg, group) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_report(&mut self,
|
||||
msg: ReportsChan,
|
||||
public_http_state: &Arc<HttpState>,
|
||||
private_http_state: &Arc<HttpState>) {
|
||||
let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None);
|
||||
let public_cache = public_http_state.http_cache.read().unwrap();
|
||||
let private_cache = private_http_state.http_cache.read().unwrap();
|
||||
|
||||
let public_report = Report {
|
||||
path: path!["memory-cache", "public"],
|
||||
kind: ReportKind::ExplicitJemallocHeapSize,
|
||||
size: public_cache.size_of(&mut ops)
|
||||
};
|
||||
|
||||
let private_report = Report {
|
||||
path: path!["memory-cache", "private"],
|
||||
kind: ReportKind::ExplicitJemallocHeapSize,
|
||||
size: private_cache.size_of(&mut ops)
|
||||
};
|
||||
|
||||
msg.send(vec!(public_report, private_report));
|
||||
}
|
||||
|
||||
/// Returns false if the thread should exit.
|
||||
fn process_msg(&mut self,
|
||||
|
@ -6,6 +6,7 @@ use ipc_channel::ipc;
|
||||
use net::resource_thread::new_core_resource_thread;
|
||||
use net::test::parse_hostsfile;
|
||||
use net_traits::CoreResourceMsg;
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::time::ProfilerChan;
|
||||
use std::net::IpAddr;
|
||||
|
||||
@ -16,9 +17,10 @@ fn ip(s: &str) -> IpAddr {
|
||||
#[test]
|
||||
fn test_exit() {
|
||||
let (tx, _rx) = ipc::channel().unwrap();
|
||||
let (mtx, _mrx) = ipc::channel().unwrap();
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let (resource_thread, _private_resource_thread) = new_core_resource_thread(
|
||||
"".into(), None, ProfilerChan(tx), None);
|
||||
"".into(), None, ProfilerChan(tx), MemProfilerChan(mtx), None);
|
||||
resource_thread.send(CoreResourceMsg::Exit(sender)).unwrap();
|
||||
receiver.recv().unwrap();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
||||
msg = {path = "../msg"}
|
||||
num-traits = "0.1.32"
|
||||
serde = "1.0"
|
||||
servo_arc = {path = "../servo_arc"}
|
||||
servo_config = {path = "../config"}
|
||||
servo_url = {path = "../url"}
|
||||
url = "1.2"
|
||||
|
@ -17,6 +17,7 @@ extern crate ipc_channel;
|
||||
extern crate msg;
|
||||
extern crate num_traits;
|
||||
#[macro_use] extern crate serde;
|
||||
extern crate servo_arc;
|
||||
extern crate servo_config;
|
||||
extern crate servo_url;
|
||||
extern crate url;
|
||||
|
@ -8,8 +8,9 @@ use {FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
|
||||
use hyper::header::{AccessControlExposeHeaders, ContentType, Headers};
|
||||
use hyper::status::StatusCode;
|
||||
use hyper_serde::Serde;
|
||||
use servo_arc::Arc;
|
||||
use servo_url::ServoUrl;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Mutex;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use serde;
|
||||
use std::marker::Send;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
@ -25,6 +26,14 @@ impl<T> OpaqueSender<T> for Sender<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OpaqueSender<T> for IpcSender<T> where T: serde::Serialize {
|
||||
fn send(&self, message: T) {
|
||||
if let Err(e) = IpcSender::send(self, message) {
|
||||
warn!("Error communicating with the target thread from the profiler: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Front-end representation of the profiler used to communicate with the
|
||||
/// profiler.
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
|
@ -462,6 +462,7 @@ fn create_constellation(user_agent: Cow<'static, str>,
|
||||
new_resource_threads(user_agent,
|
||||
devtools_chan.clone(),
|
||||
time_profiler_chan.clone(),
|
||||
mem_profiler_chan.clone(),
|
||||
config_dir);
|
||||
let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(),
|
||||
webrender_api_sender.create_api());
|
||||
|
@ -489,6 +489,7 @@ pub mod root {
|
||||
pub const NS_STYLE_WIDTH_MIN_CONTENT: u32 = 1;
|
||||
pub const NS_STYLE_WIDTH_FIT_CONTENT: u32 = 2;
|
||||
pub const NS_STYLE_WIDTH_AVAILABLE: u32 = 3;
|
||||
pub const NS_STYLE_FLEX_BASIS_CONTENT: u32 = 4;
|
||||
pub const NS_STYLE_POSITION_STATIC: u32 = 0;
|
||||
pub const NS_STYLE_POSITION_RELATIVE: u32 = 1;
|
||||
pub const NS_STYLE_POSITION_ABSOLUTE: u32 = 2;
|
||||
|
@ -10,7 +10,7 @@ use Atom;
|
||||
use app_units::Au;
|
||||
use counter_style::{Symbol, Symbols};
|
||||
use cssparser::RGBA;
|
||||
use gecko_bindings::structs::{CounterStylePtr, nsStyleCoord};
|
||||
use gecko_bindings::structs::{self, CounterStylePtr, nsStyleCoord};
|
||||
use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius};
|
||||
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
||||
use media_queries::Device;
|
||||
@ -21,10 +21,12 @@ use values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage, Length
|
||||
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
|
||||
use values::computed::{MaxLength, MozLength, Percentage};
|
||||
use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber};
|
||||
use values::computed::FlexBasis as ComputedFlexBasis;
|
||||
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
|
||||
use values::generics::{CounterStyleOrNone, NonNegative};
|
||||
use values::generics::basic_shape::ShapeRadius;
|
||||
use values::generics::box_::Perspective;
|
||||
use values::generics::flex::FlexBasis;
|
||||
use values::generics::gecko::ScrollSnapPoint;
|
||||
use values::generics::grid::{TrackBreadth, TrackKeyword};
|
||||
|
||||
@ -59,6 +61,31 @@ impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoo
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for ComputedFlexBasis {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
match *self {
|
||||
FlexBasis::Content => {
|
||||
coord.set_value(
|
||||
CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT)
|
||||
)
|
||||
},
|
||||
FlexBasis::Width(ref w) => w.to_gecko_style_coord(coord),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
if let Some(width) = MozLength::from_gecko_style_coord(coord) {
|
||||
return Some(FlexBasis::Width(width))
|
||||
}
|
||||
|
||||
if let CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT) = coord.as_value() {
|
||||
return Some(FlexBasis::Content)
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for Number {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
coord.set_value(CoordDataValue::Factor(*self));
|
||||
|
@ -1445,7 +1445,8 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
||||
"length::LengthOrAuto": impl_style_coord,
|
||||
"length::LengthOrNormal": impl_style_coord,
|
||||
"length::NonNegativeLengthOrAuto": impl_style_coord,
|
||||
"length::NonNegativeLengthOrNormal": impl_style_coord,
|
||||
"length::NonNegativeLengthOrPercentageOrNormal": impl_style_coord,
|
||||
"FlexBasis": impl_style_coord,
|
||||
"Length": impl_absolute_length,
|
||||
"LengthOrNormal": impl_style_coord,
|
||||
"LengthOrPercentage": impl_style_coord,
|
||||
@ -1748,14 +1749,14 @@ fn static_assert() {
|
||||
|
||||
<% skip_position_longhands = " ".join(x.ident for x in SIDES + GRID_LINES) %>
|
||||
<%self:impl_trait style_struct_name="Position"
|
||||
skip_longhands="${skip_position_longhands} z-index order align-content
|
||||
justify-content align-self justify-self align-items
|
||||
justify-items grid-auto-rows grid-auto-columns grid-auto-flow
|
||||
grid-template-areas grid-template-rows grid-template-columns">
|
||||
skip_longhands="${skip_position_longhands} z-index order
|
||||
align-content justify-content align-self
|
||||
justify-self align-items justify-items
|
||||
grid-auto-rows grid-auto-columns
|
||||
grid-auto-flow grid-template-areas
|
||||
grid-template-rows grid-template-columns">
|
||||
% for side in SIDES:
|
||||
<% impl_split_style_coord("%s" % side.ident,
|
||||
"mOffset",
|
||||
side.index) %>
|
||||
<% impl_split_style_coord(side.ident, "mOffset", side.index) %>
|
||||
% endfor
|
||||
|
||||
pub fn set_z_index(&mut self, v: longhands::z_index::computed_value::T) {
|
||||
|
@ -29,14 +29,21 @@ ${helpers.predefined_type(
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type("column-gap",
|
||||
"length::NonNegativeLengthOrNormal",
|
||||
"Either::Second(Normal)",
|
||||
extra_prefixes="moz",
|
||||
servo_pref="layout.columns.enabled",
|
||||
animation_value_type="NonNegativeLengthOrNormal",
|
||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap",
|
||||
servo_restyle_damage = "reflow")}
|
||||
|
||||
<%
|
||||
# FIXME(#20498): Servo should support percentages in column-gap.
|
||||
col_gap_type = "NonNegativeLengthOrPercentageOrNormal" if product == "gecko" else "NonNegativeLengthOrNormal"
|
||||
%>
|
||||
${helpers.predefined_type(
|
||||
"column-gap",
|
||||
"length::%s" % col_gap_type,
|
||||
"Either::Second(Normal)",
|
||||
extra_prefixes="moz",
|
||||
servo_pref="layout.columns.enabled",
|
||||
animation_value_type=col_gap_type,
|
||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap",
|
||||
servo_restyle_damage = "reflow",
|
||||
)}
|
||||
|
||||
${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
|
||||
products="gecko", animation_value_type="discrete",
|
||||
|
@ -206,93 +206,15 @@ ${helpers.predefined_type(
|
||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
|
||||
)}
|
||||
|
||||
<%helpers:longhand name="text-emphasis-position" animation_value_type="discrete" products="gecko"
|
||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position">
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
|
||||
#[derive(ToComputedValue, ToCss)]
|
||||
pub enum HorizontalWritingModeValue {
|
||||
Over,
|
||||
Under,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
|
||||
#[derive(ToComputedValue, ToCss)]
|
||||
pub enum VerticalWritingModeValue {
|
||||
Right,
|
||||
Left,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
|
||||
pub struct SpecifiedValue(pub HorizontalWritingModeValue, pub VerticalWritingModeValue);
|
||||
|
||||
pub mod computed_value {
|
||||
pub type T = super::SpecifiedValue;
|
||||
}
|
||||
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
SpecifiedValue(HorizontalWritingModeValue::Over, VerticalWritingModeValue::Right)
|
||||
}
|
||||
|
||||
pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
-> Result<SpecifiedValue, ParseError<'i>> {
|
||||
if let Ok(horizontal) = input.try(|input| HorizontalWritingModeValue::parse(input)) {
|
||||
let vertical = VerticalWritingModeValue::parse(input)?;
|
||||
Ok(SpecifiedValue(horizontal, vertical))
|
||||
} else {
|
||||
let vertical = VerticalWritingModeValue::parse(input)?;
|
||||
let horizontal = HorizontalWritingModeValue::parse(input)?;
|
||||
Ok(SpecifiedValue(horizontal, vertical))
|
||||
}
|
||||
}
|
||||
|
||||
% if product == "gecko":
|
||||
impl SpecifiedValue {
|
||||
pub fn from_gecko_keyword(kw: u32) -> Self {
|
||||
use gecko_bindings::structs;
|
||||
|
||||
let vert = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT != 0 {
|
||||
VerticalWritingModeValue::Right
|
||||
} else {
|
||||
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT != 0);
|
||||
VerticalWritingModeValue::Left
|
||||
};
|
||||
let horiz = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER != 0 {
|
||||
HorizontalWritingModeValue::Over
|
||||
} else {
|
||||
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER != 0);
|
||||
HorizontalWritingModeValue::Under
|
||||
};
|
||||
SpecifiedValue(horiz, vert)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for SpecifiedValue {
|
||||
fn from(bits: u8) -> SpecifiedValue {
|
||||
SpecifiedValue::from_gecko_keyword(bits as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpecifiedValue> for u8 {
|
||||
fn from(v: SpecifiedValue) -> u8 {
|
||||
use gecko_bindings::structs;
|
||||
|
||||
let mut result = match v.0 {
|
||||
HorizontalWritingModeValue::Over => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER,
|
||||
HorizontalWritingModeValue::Under => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER,
|
||||
};
|
||||
match v.1 {
|
||||
VerticalWritingModeValue::Right => {
|
||||
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT;
|
||||
}
|
||||
VerticalWritingModeValue::Left => {
|
||||
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT;
|
||||
}
|
||||
};
|
||||
result as u8
|
||||
}
|
||||
}
|
||||
% endif
|
||||
</%helpers:longhand>
|
||||
${helpers.predefined_type(
|
||||
"text-emphasis-position",
|
||||
"TextEmphasisPosition",
|
||||
"computed::TextEmphasisPosition::over_right()",
|
||||
initial_specified_value="specified::TextEmphasisPosition::over_right()",
|
||||
products="gecko",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"text-emphasis-color",
|
||||
|
@ -174,32 +174,16 @@ ${helpers.predefined_type("order", "Integer", "0",
|
||||
spec="https://drafts.csswg.org/css-flexbox/#order-property",
|
||||
servo_restyle_damage = "reflow")}
|
||||
|
||||
% if product == "gecko":
|
||||
// FIXME: Gecko doesn't support content value yet.
|
||||
//
|
||||
// FIXME(emilio): I suspect this property shouldn't allow quirks, and this
|
||||
// was just a mistake, it's kind of justificable to support it given the
|
||||
// spec grammar is just `content | <width>`, but other browsers don't...
|
||||
${helpers.predefined_type(
|
||||
"flex-basis",
|
||||
"MozLength",
|
||||
"computed::MozLength::auto()",
|
||||
extra_prefixes="webkit",
|
||||
animation_value_type="MozLength",
|
||||
allow_quirks=True,
|
||||
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
|
||||
servo_restyle_damage = "reflow"
|
||||
)}
|
||||
% else:
|
||||
// FIXME: This property should be animatable.
|
||||
${helpers.predefined_type("flex-basis",
|
||||
"FlexBasis",
|
||||
"computed::FlexBasis::auto()",
|
||||
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
|
||||
extra_prefixes="webkit",
|
||||
animation_value_type="none",
|
||||
servo_restyle_damage = "reflow")}
|
||||
% endif
|
||||
${helpers.predefined_type(
|
||||
"flex-basis",
|
||||
"FlexBasis",
|
||||
"computed::FlexBasis::auto()",
|
||||
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
|
||||
extra_prefixes="webkit",
|
||||
animation_value_type="FlexBasis",
|
||||
servo_restyle_damage = "reflow"
|
||||
)}
|
||||
|
||||
% for (size, logical) in ALL_SIZES:
|
||||
<%
|
||||
spec = "https://drafts.csswg.org/css-box/#propdef-%s"
|
||||
|
@ -4,8 +4,23 @@
|
||||
|
||||
//! Computed types for CSS values related to flexbox.
|
||||
|
||||
use values::computed::length::LengthOrPercentage;
|
||||
use values::generics::flex::FlexBasis as GenericFlexBasis;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "servo")]
|
||||
pub type Width = ::values::computed::NonNegativeLengthOrPercentageOrAuto;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type Width = ::values::computed::MozLength;
|
||||
|
||||
/// A computed value for the `flex-basis` property.
|
||||
pub type FlexBasis = GenericFlexBasis<LengthOrPercentage>;
|
||||
pub type FlexBasis = GenericFlexBasis<Width>;
|
||||
|
||||
impl FlexBasis {
|
||||
/// `auto`
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
GenericFlexBasis::Width(Width::auto())
|
||||
}
|
||||
}
|
||||
|
@ -427,10 +427,10 @@ impl LengthOrPercentage {
|
||||
pub fn clamp_to_non_negative(self) -> Self {
|
||||
match self {
|
||||
LengthOrPercentage::Length(length) => {
|
||||
LengthOrPercentage::Length(Length::new(length.px().max(0.)))
|
||||
LengthOrPercentage::Length(length.clamp_to_non_negative())
|
||||
},
|
||||
LengthOrPercentage::Percentage(percentage) => {
|
||||
LengthOrPercentage::Percentage(Percentage(percentage.0.max(0.)))
|
||||
LengthOrPercentage::Percentage(percentage.clamp_to_non_negative())
|
||||
},
|
||||
_ => self
|
||||
}
|
||||
@ -511,6 +511,31 @@ impl LengthOrPercentageOrAuto {
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper of LengthOrPercentageOrAuto, whose value must be >= 0.
|
||||
pub type NonNegativeLengthOrPercentageOrAuto = NonNegative<LengthOrPercentageOrAuto>;
|
||||
|
||||
impl NonNegativeLengthOrPercentageOrAuto {
|
||||
/// `auto`
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
NonNegative(LengthOrPercentageOrAuto::Auto)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToAnimatedValue for NonNegativeLengthOrPercentageOrAuto {
|
||||
type AnimatedValue = LengthOrPercentageOrAuto;
|
||||
|
||||
#[inline]
|
||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||
NonNegative(animated.clamp_to_non_negative())
|
||||
}
|
||||
}
|
||||
|
||||
impl LengthOrPercentageOrAuto {
|
||||
/// Returns true if the computed value is absolute 0 or 0%.
|
||||
///
|
||||
@ -524,6 +549,15 @@ impl LengthOrPercentageOrAuto {
|
||||
Calc(_) | Auto => false
|
||||
}
|
||||
}
|
||||
|
||||
fn clamp_to_non_negative(self) -> Self {
|
||||
use self::LengthOrPercentageOrAuto::*;
|
||||
match self {
|
||||
Length(l) => Length(l.clamp_to_non_negative()),
|
||||
Percentage(p) => Percentage(p.clamp_to_non_negative()),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for specified::LengthOrPercentageOrAuto {
|
||||
@ -737,6 +771,11 @@ impl CSSPixelLength {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clamp_to_non_negative(self) -> Self {
|
||||
Self::new(self.px().max(0.))
|
||||
}
|
||||
|
||||
/// Return the length with app_unit i32 type.
|
||||
#[inline]
|
||||
pub fn to_i32_au(&self) -> i32 {
|
||||
@ -897,6 +936,9 @@ pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
|
||||
/// Either a computed NonNegativeLength or the `normal` keyword.
|
||||
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
|
||||
|
||||
/// Either a computed NonNegativeLengthOrPercentage or the `normal` keyword.
|
||||
pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPercentage, Normal>;
|
||||
|
||||
/// A type for possible values for min- and max- flavors of width, height,
|
||||
/// block-size, and inline-size.
|
||||
#[allow(missing_docs)]
|
||||
|
@ -60,7 +60,8 @@ pub use super::{Auto, Either, None_};
|
||||
pub use super::specified::{BorderStyle, TextDecorationLine};
|
||||
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage};
|
||||
pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength};
|
||||
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength, NonNegativeLengthOrPercentage};
|
||||
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
|
||||
pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto};
|
||||
pub use self::list::{ListStyleImage, Quotes};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::list::ListStyleType;
|
||||
@ -75,7 +76,7 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
||||
pub use self::svg::MozContextProperties;
|
||||
pub use self::table::XSpan;
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize};
|
||||
pub use self::text::{TextAlign, TextEmphasisStyle, TextOverflow, WordSpacing};
|
||||
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle, TextOverflow, WordSpacing};
|
||||
pub use self::time::Time;
|
||||
pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation};
|
||||
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
||||
|
@ -32,6 +32,12 @@ impl Percentage {
|
||||
pub fn abs(&self) -> Self {
|
||||
Percentage(self.0.abs())
|
||||
}
|
||||
|
||||
/// Clamps this percentage to a non-negative percentage.
|
||||
#[inline]
|
||||
pub fn clamp_to_non_negative(self) -> Self {
|
||||
Percentage(self.0.max(0.))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Percentage {
|
||||
|
@ -18,6 +18,7 @@ use values::generics::text::Spacing;
|
||||
use values::specified::text::{TextDecorationLine, TextEmphasisFillMode, TextEmphasisShapeKeyword, TextOverflowSide};
|
||||
|
||||
pub use values::specified::TextAlignKeyword as TextAlign;
|
||||
pub use values::specified::TextEmphasisPosition;
|
||||
|
||||
/// A computed value for the `initial-letter` property.
|
||||
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
||||
|
@ -4,34 +4,13 @@
|
||||
|
||||
//! Generic types for CSS values related to flexbox.
|
||||
|
||||
use values::computed::Percentage;
|
||||
|
||||
/// A generic value for the `flex-basis` property.
|
||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
|
||||
pub enum FlexBasis<LengthOrPercentage> {
|
||||
/// `auto`
|
||||
Auto,
|
||||
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)]
|
||||
#[derive(ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
|
||||
pub enum FlexBasis<Width> {
|
||||
/// `content`
|
||||
Content,
|
||||
/// `<length-percentage>`
|
||||
Length(LengthOrPercentage),
|
||||
}
|
||||
|
||||
impl<L> FlexBasis<L> {
|
||||
/// Returns `auto`.
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
FlexBasis::Auto
|
||||
}
|
||||
}
|
||||
|
||||
impl<L> FlexBasis<L>
|
||||
where Percentage: Into<L>,
|
||||
{
|
||||
/// Returns `0%`.
|
||||
#[inline]
|
||||
pub fn zero_percent() -> Self {
|
||||
FlexBasis::Length(Percentage(0.).into())
|
||||
}
|
||||
/// `<width>`
|
||||
Width(Width),
|
||||
}
|
||||
|
@ -8,22 +8,42 @@ use cssparser::Parser;
|
||||
use parser::{Parse, ParserContext};
|
||||
use style_traits::ParseError;
|
||||
use values::generics::flex::FlexBasis as GenericFlexBasis;
|
||||
use values::specified::length::LengthOrPercentage;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "servo")]
|
||||
pub type Width = ::values::specified::NonNegativeLengthOrPercentageOrAuto;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type Width = ::values::specified::MozLength;
|
||||
|
||||
/// A specified value for the `flex-basis` property.
|
||||
pub type FlexBasis = GenericFlexBasis<LengthOrPercentage>;
|
||||
pub type FlexBasis = GenericFlexBasis<Width>;
|
||||
|
||||
impl Parse for FlexBasis {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>)
|
||||
-> Result<Self, ParseError<'i>> {
|
||||
if let Ok(length) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
return Ok(GenericFlexBasis::Length(length));
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(width) = input.try(|i| Width::parse(context, i)) {
|
||||
return Ok(GenericFlexBasis::Width(width));
|
||||
}
|
||||
try_match_ident_ignore_ascii_case! { input,
|
||||
"auto" => Ok(GenericFlexBasis::Auto),
|
||||
"content" => Ok(GenericFlexBasis::Content),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FlexBasis {
|
||||
/// `auto`
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
GenericFlexBasis::Width(Width::auto())
|
||||
}
|
||||
|
||||
/// `0%`
|
||||
#[inline]
|
||||
pub fn zero_percent() -> Self {
|
||||
GenericFlexBasis::Width(Width::zero_percent())
|
||||
}
|
||||
}
|
||||
|
@ -679,9 +679,6 @@ impl NonNegativeLength {
|
||||
}
|
||||
}
|
||||
|
||||
/// Either a NonNegativeLength or the `normal` keyword.
|
||||
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
|
||||
|
||||
/// Either a NonNegativeLength or the `auto` keyword.
|
||||
pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
|
||||
|
||||
@ -917,6 +914,16 @@ impl LengthOrPercentageOrAuto {
|
||||
pub fn zero_percent() -> Self {
|
||||
LengthOrPercentageOrAuto::Percentage(computed::Percentage::zero())
|
||||
}
|
||||
|
||||
/// Parses, with quirks.
|
||||
#[inline]
|
||||
pub fn parse_quirky<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for LengthOrPercentageOrAuto {
|
||||
@ -926,14 +933,33 @@ impl Parse for LengthOrPercentageOrAuto {
|
||||
}
|
||||
}
|
||||
|
||||
impl LengthOrPercentageOrAuto {
|
||||
/// Parses, with quirks.
|
||||
/// A wrapper of LengthOrPercentageOrAuto, whose value must be >= 0.
|
||||
pub type NonNegativeLengthOrPercentageOrAuto = NonNegative<LengthOrPercentageOrAuto>;
|
||||
|
||||
impl NonNegativeLengthOrPercentageOrAuto {
|
||||
/// 0
|
||||
#[inline]
|
||||
pub fn parse_quirky<'i, 't>(context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks)
|
||||
-> Result<Self, ParseError<'i>> {
|
||||
Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
|
||||
pub fn zero() -> Self {
|
||||
NonNegative(LengthOrPercentageOrAuto::zero())
|
||||
}
|
||||
|
||||
/// 0%
|
||||
#[inline]
|
||||
pub fn zero_percent() -> Self {
|
||||
NonNegative(LengthOrPercentageOrAuto::zero_percent())
|
||||
}
|
||||
|
||||
/// `auto`
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
NonNegative(LengthOrPercentageOrAuto::Auto)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for NonNegativeLengthOrPercentageOrAuto {
|
||||
#[inline]
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
Ok(NonNegative(LengthOrPercentageOrAuto::parse_non_negative(context, input)?))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1020,6 +1046,12 @@ impl Parse for LengthOrPercentageOrNone {
|
||||
/// A wrapper of LengthOrPercentage, whose value must be >= 0.
|
||||
pub type NonNegativeLengthOrPercentage = NonNegative<LengthOrPercentage>;
|
||||
|
||||
/// Either a computed NonNegativeLength or the `normal` keyword.
|
||||
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
|
||||
|
||||
/// Either a NonNegativeLengthOrPercentage or the `normal` keyword.
|
||||
pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPercentage, Normal>;
|
||||
|
||||
impl From<NoCalcLength> for NonNegativeLengthOrPercentage {
|
||||
#[inline]
|
||||
fn from(len: NoCalcLength) -> Self {
|
||||
@ -1087,8 +1119,11 @@ impl LengthOrNumber {
|
||||
}
|
||||
|
||||
/// A value suitable for a `min-width` or `min-height` property.
|
||||
/// Unlike `max-width` or `max-height` properties, a MozLength can be
|
||||
/// `auto`, and cannot be `none`.
|
||||
///
|
||||
/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`,
|
||||
/// and cannot be `none`.
|
||||
///
|
||||
/// Note that it only accepts non-negative values.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
|
||||
pub enum MozLength {
|
||||
|
@ -55,7 +55,7 @@ pub use self::length::{FontRelativeLength, Length, LengthOrNumber};
|
||||
pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength};
|
||||
pub use self::length::{NoCalcLength, ViewportPercentageLength};
|
||||
pub use self::length::NonNegativeLengthOrPercentage;
|
||||
pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto};
|
||||
pub use self::list::{ListStyleImage, Quotes};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::list::ListStyleType;
|
||||
@ -71,7 +71,8 @@ pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
|
||||
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
||||
pub use self::svg::MozContextProperties;
|
||||
pub use self::table::XSpan;
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign, TextEmphasisStyle};
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign};
|
||||
pub use self::text::{TextEmphasisStyle, TextEmphasisPosition};
|
||||
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
|
||||
pub use self::time::Time;
|
||||
pub use self::transform::{Rotate, Scale, TimingFunction, Transform};
|
||||
|
@ -666,6 +666,106 @@ impl Parse for TextEmphasisStyle {
|
||||
}
|
||||
}
|
||||
|
||||
/// The allowed horizontal values for the `text-emphasis-position` property.
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
|
||||
#[derive(ToComputedValue, ToCss)]
|
||||
pub enum TextEmphasisHorizontalWritingModeValue {
|
||||
/// Draw marks over the text in horizontal writing mode.
|
||||
Over,
|
||||
/// Draw marks under the text in horizontal writing mode.
|
||||
Under,
|
||||
}
|
||||
|
||||
/// The allowed vertical values for the `text-emphasis-position` property.
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
|
||||
#[derive(ToComputedValue, ToCss)]
|
||||
pub enum TextEmphasisVerticalWritingModeValue {
|
||||
/// Draws marks to the right of the text in vertical writing mode.
|
||||
Right,
|
||||
/// Draw marks to the left of the text in vertical writing mode.
|
||||
Left,
|
||||
}
|
||||
|
||||
/// Specified value of `text-emphasis-position` property.
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
|
||||
pub struct TextEmphasisPosition(
|
||||
pub TextEmphasisHorizontalWritingModeValue,
|
||||
pub TextEmphasisVerticalWritingModeValue
|
||||
);
|
||||
|
||||
impl TextEmphasisPosition {
|
||||
#[inline]
|
||||
/// Returns the initial value of `text-emphasis-position`
|
||||
pub fn over_right() -> Self {
|
||||
TextEmphasisPosition(TextEmphasisHorizontalWritingModeValue::Over,
|
||||
TextEmphasisVerticalWritingModeValue::Right)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
/// Converts an enumerated value coming from Gecko to a `TextEmphasisPosition`.
|
||||
pub fn from_gecko_keyword(kw: u32) -> Self {
|
||||
use gecko_bindings::structs;
|
||||
|
||||
let vert = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT != 0 {
|
||||
TextEmphasisVerticalWritingModeValue::Right
|
||||
} else {
|
||||
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT != 0);
|
||||
TextEmphasisVerticalWritingModeValue::Left
|
||||
};
|
||||
let horiz = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER != 0 {
|
||||
TextEmphasisHorizontalWritingModeValue::Over
|
||||
} else {
|
||||
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER != 0);
|
||||
TextEmphasisHorizontalWritingModeValue::Under
|
||||
};
|
||||
TextEmphasisPosition(horiz, vert)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for TextEmphasisPosition {
|
||||
fn parse<'i, 't>(
|
||||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(horizontal) = input.try(|input| TextEmphasisHorizontalWritingModeValue::parse(input)) {
|
||||
let vertical = TextEmphasisVerticalWritingModeValue::parse(input)?;
|
||||
Ok(TextEmphasisPosition(horizontal, vertical))
|
||||
} else {
|
||||
let vertical = TextEmphasisVerticalWritingModeValue::parse(input)?;
|
||||
let horizontal = TextEmphasisHorizontalWritingModeValue::parse(input)?;
|
||||
Ok(TextEmphasisPosition(horizontal, vertical))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl From<u8> for TextEmphasisPosition {
|
||||
fn from(bits: u8) -> Self {
|
||||
TextEmphasisPosition::from_gecko_keyword(bits as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl From<TextEmphasisPosition> for u8 {
|
||||
fn from(v: TextEmphasisPosition) -> u8 {
|
||||
use gecko_bindings::structs;
|
||||
|
||||
let mut result = match v.0 {
|
||||
TextEmphasisHorizontalWritingModeValue::Over => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER,
|
||||
TextEmphasisHorizontalWritingModeValue::Under => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER,
|
||||
};
|
||||
match v.1 {
|
||||
TextEmphasisVerticalWritingModeValue::Right => {
|
||||
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT;
|
||||
}
|
||||
TextEmphasisVerticalWritingModeValue::Left => {
|
||||
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT;
|
||||
}
|
||||
};
|
||||
result as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified value for the `-moz-tab-size` property.
|
||||
pub type MozTabSize = GenericMozTabSize<NonNegativeNumber, NonNegativeLength>;
|
||||
|
||||
|
@ -8,7 +8,6 @@ use style::properties::{PropertyDeclaration, Importance};
|
||||
use style::properties::declaration_block::PropertyDeclarationBlock;
|
||||
use style::properties::parse_property_declaration_list;
|
||||
use style::values::{CustomIdent, RGBA};
|
||||
use style::values::generics::flex::FlexBasis;
|
||||
use style::values::specified::{BorderStyle, BorderSideWidth, Color};
|
||||
use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
use style::values::specified::NoCalcLength;
|
||||
@ -559,42 +558,6 @@ mod shorthand_serialization {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flex_should_serialize_all_available_properties() {
|
||||
use style::values::specified::{NonNegativeNumber, Percentage};
|
||||
|
||||
let mut properties = Vec::new();
|
||||
|
||||
let grow = NonNegativeNumber::new(2f32);
|
||||
let shrink = NonNegativeNumber::new(3f32);
|
||||
let basis =
|
||||
FlexBasis::Length(Percentage::new(0.5f32).into());
|
||||
|
||||
properties.push(PropertyDeclaration::FlexGrow(grow));
|
||||
properties.push(PropertyDeclaration::FlexShrink(shrink));
|
||||
properties.push(PropertyDeclaration::FlexBasis(basis));
|
||||
|
||||
let serialization = shorthand_properties_to_string(properties);
|
||||
assert_eq!(serialization, "flex: 2 3 50%;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flex_flow_should_serialize_all_available_properties() {
|
||||
use style::properties::longhands::flex_direction::SpecifiedValue as FlexDirection;
|
||||
use style::properties::longhands::flex_wrap::SpecifiedValue as FlexWrap;
|
||||
|
||||
let mut properties = Vec::new();
|
||||
|
||||
let direction = FlexDirection::Row;
|
||||
let wrap = FlexWrap::Wrap;
|
||||
|
||||
properties.push(PropertyDeclaration::FlexDirection(direction));
|
||||
properties.push(PropertyDeclaration::FlexWrap(wrap));
|
||||
|
||||
let serialization = shorthand_properties_to_string(properties);
|
||||
assert_eq!(serialization, "flex-flow: row wrap;");
|
||||
}
|
||||
|
||||
mod background {
|
||||
use super::*;
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
[column-gap-parsing-001.html]
|
||||
[column-gap accepts percentage]
|
||||
expected: FAIL
|
||||
|
@ -1,4 +0,0 @@
|
||||
[grid-column-gap-parsing-001.html]
|
||||
[column-gap accepts percentage]
|
||||
expected: FAIL
|
||||
|
@ -1,37 +1,7 @@
|
||||
[multicol-gap-percentage-001.html]
|
||||
[.multicol 1]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 2]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 3]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 4]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 5]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 6]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 7]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 8]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 9]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 10]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 11]
|
||||
expected: FAIL
|
||||
|
||||
[.multicol 12]
|
||||
expected: FAIL
|
||||
|
||||
|
1
third_party/rust/hyper_serde/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/hyper_serde/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{".travis.yml":"bdb52df624876cdf4a9214bb2a81cefcf7ed7176b7213045846a68ead3a5c56f","Cargo.toml":"5d897604ce6935387b66cb58cbd15af0fbf70a6f9aa18dc5a524d92946cb4fcb","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"d5b3226768e22b6dd11270c92e1e4bab9acdfa7e5b2fc1efaddcf3fbf00aff05","README.md":"e4d2cfe8f354ea78d25b51d817ed172c8569b434badaec74b4e8551f30be01e9","bors.toml":"1d8a7a56c5c76925a3daa8c50a40cc82cbfc638f521f864106bd60b1e8a219a2","rustfmt.toml":"cad0c47fc0d3c55c5c2144efc4935f830bf720190267c416b9ee484ebbc3604d","src/lib.rs":"1d58d926c22e1027f0037609176361b19a9693d582f9e5349440eebd72d62d79","tests/supported.rs":"29912bd33d6b6ea0b8985f23b75af4ef4419017ce5cd4b3bc1fc8349af2e0952","tests/tokens.rs":"d7effb9466553820a65bee2ed250c93d60cffe7065fdf6d389e967ef80297efc"},"package":"0997ad463f64ce6ba02cf5af320622bb9782e4f8355b650a2cc7ccca69a7cc2e"}
|
8
third_party/rust/hyper_serde/.travis.yml
vendored
Normal file
8
third_party/rust/hyper_serde/.travis.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
language: rust
|
||||
rust:
|
||||
- nightly
|
||||
- beta
|
||||
- stable
|
||||
branches:
|
||||
except:
|
||||
- staging.tmp
|
50
third_party/rust/hyper_serde/Cargo.toml
vendored
Normal file
50
third_party/rust/hyper_serde/Cargo.toml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "hyper_serde"
|
||||
version = "0.8.0"
|
||||
authors = ["Anthony Ramine <n.oxyde@gmail.com>"]
|
||||
description = "Serde support for Hyper types"
|
||||
documentation = "https://docs.rs/hyper_serde"
|
||||
keywords = ["serde", "serialization", "hyper", "cookie", "mime"]
|
||||
categories = ["encoding", "web-programming"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/nox/hyper_serde"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
[dependencies.time]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.cookie]
|
||||
version = "0.10"
|
||||
default-features = false
|
||||
|
||||
[dependencies.mime]
|
||||
version = "0.2"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.hyper]
|
||||
version = "0.10"
|
||||
|
||||
[dependencies.serde_bytes]
|
||||
version = "0.10"
|
||||
[dev-dependencies.serde_test]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.time]
|
||||
version = "0.1"
|
||||
[badges.travis-ci]
|
||||
repository = "nox/hyper_serde"
|
176
third_party/rust/hyper_serde/LICENSE-APACHE
vendored
Normal file
176
third_party/rust/hyper_serde/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
19
third_party/rust/hyper_serde/LICENSE-MIT
vendored
Normal file
19
third_party/rust/hyper_serde/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2016 Anthony Ramine
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
40
third_party/rust/hyper_serde/README.md
vendored
Normal file
40
third_party/rust/hyper_serde/README.md
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
Serde support for Hyper types
|
||||
=============================
|
||||
|
||||
This crate provides wrappers and convenience functions to support [Serde] for
|
||||
some types defined in [cookie], [Hyper], [mime] and [time].
|
||||
|
||||
[cookie]: https://github.com/alexcrichton/cookie-rs
|
||||
[Hyper]: https://github.com/hyperium/hyper
|
||||
[mime]: https://github.com/hyperium/mime.rs
|
||||
[Serde]: https://github.com/serde-rs/serde
|
||||
[time]: https://github.com/rust-lang-deprecated/time
|
||||
|
||||
The supported types are:
|
||||
|
||||
* `cookie::Cookie`
|
||||
* `hyper::header::ContentType`
|
||||
* `hyper::header::Headers`
|
||||
* `hyper::http::RawStatus`
|
||||
* `hyper::method::Method`
|
||||
* `mime::Mime`
|
||||
* `time::Tm`
|
||||
|
||||
For more details, see the crate documentation.
|
||||
|
||||
## License
|
||||
|
||||
hyper_serde is licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in hyper_serde by you, as defined in the Apache-2.0 license,
|
||||
shall be dual licensed as above, without any additional terms or conditions.
|
1
third_party/rust/hyper_serde/bors.toml
vendored
Normal file
1
third_party/rust/hyper_serde/bors.toml
vendored
Normal file
@ -0,0 +1 @@
|
||||
status = ["continuous-integration/travis-ci/push"]
|
8
third_party/rust/hyper_serde/rustfmt.toml
vendored
Normal file
8
third_party/rust/hyper_serde/rustfmt.toml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
match_block_trailing_comma = true
|
||||
max_width = 80
|
||||
newline_style = "Unix"
|
||||
normalize_comments = true
|
||||
reorder_imported_names = true
|
||||
reorder_imports = true
|
||||
use_try_shorthand = true
|
||||
where_trailing_comma = true
|
536
third_party/rust/hyper_serde/src/lib.rs
vendored
Normal file
536
third_party/rust/hyper_serde/src/lib.rs
vendored
Normal file
@ -0,0 +1,536 @@
|
||||
//! This crate provides wrappers and convenience functions to make Hyper and
|
||||
//! Serde work hand in hand.
|
||||
//!
|
||||
//! The supported types are:
|
||||
//!
|
||||
//! * `cookie::Cookie`
|
||||
//! * `hyper::header::ContentType`
|
||||
//! * `hyper::header::Headers`
|
||||
//! * `hyper::http::RawStatus`
|
||||
//! * `hyper::method::Method`
|
||||
//! * `mime::Mime`
|
||||
//! * `time::Tm`
|
||||
//!
|
||||
//! # How do I use a data type with a `Headers` member with Serde?
|
||||
//!
|
||||
//! Use the serde attributes `deserialize_with` and `serialize_with`.
|
||||
//!
|
||||
//! ```
|
||||
//! struct MyStruct {
|
||||
//! #[serde(deserialize_with = "hyper_serde::deserialize",
|
||||
//! serialize_with = "hyper_serde::serialize")]
|
||||
//! headers: Headers,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # How do I encode a `Headers` value with `serde_json::to_string`?
|
||||
//!
|
||||
//! Use the `Ser` wrapper.
|
||||
//!
|
||||
//! ```
|
||||
//! serde_json::to_string(&Ser::new(&headers))
|
||||
//! ```
|
||||
//!
|
||||
//! # How do I decode a `Method` value with `serde_json::parse`?
|
||||
//!
|
||||
//! Use the `De` wrapper.
|
||||
//!
|
||||
//! ```
|
||||
//! serde_json::parse::<De<Method>>("\"PUT\"").map(De::into_inner)
|
||||
//! ```
|
||||
//!
|
||||
//! # How do I send `Cookie` values as part of an IPC channel?
|
||||
//!
|
||||
//! Use the `Serde` wrapper. It implements `Deref` and `DerefMut` for
|
||||
//! convenience.
|
||||
//!
|
||||
//! ```
|
||||
//! ipc::channel::<Serde<Cookie>>()
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
extern crate cookie;
|
||||
extern crate hyper;
|
||||
extern crate mime;
|
||||
extern crate serde;
|
||||
extern crate serde_bytes;
|
||||
extern crate time;
|
||||
|
||||
use cookie::Cookie;
|
||||
use hyper::header::{ContentType, Headers};
|
||||
use hyper::http::RawStatus;
|
||||
use hyper::method::Method;
|
||||
use mime::Mime;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_bytes::{ByteBuf, Bytes};
|
||||
use serde::de::{self, MapAccess, SeqAccess, Visitor};
|
||||
use serde::ser::{SerializeMap, SerializeSeq};
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str;
|
||||
use time::{Tm, strptime};
|
||||
|
||||
/// Deserialises a `T` value with a given deserializer.
|
||||
///
|
||||
/// This is useful to deserialize Hyper types used in structure fields or
|
||||
/// tuple members with `#[serde(deserialize_with = "hyper_serde::deserialize")]`.
|
||||
#[inline(always)]
|
||||
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
De<T>: Deserialize<'de>,
|
||||
{
|
||||
De::deserialize(deserializer).map(De::into_inner)
|
||||
}
|
||||
|
||||
/// Serialises `value` with a given serializer.
|
||||
///
|
||||
/// This is useful to serialize Hyper types used in structure fields or
|
||||
/// tuple members with `#[serde(serialize_with = "hyper_serde::serialize")]`.
|
||||
#[inline(always)]
|
||||
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
Ser::new(value).serialize(serializer)
|
||||
}
|
||||
|
||||
/// Serialises `value` with a given serializer in a pretty way.
|
||||
///
|
||||
/// This does the same job as `serialize` but with a prettier format
|
||||
/// for some combinations of types and serialisers.
|
||||
///
|
||||
/// For now, the only change from `serialize` is when serialising `Headers`,
|
||||
/// where the items in the header values get serialised as strings instead
|
||||
/// of sequences of bytes, if they represent UTF-8 text.
|
||||
#[inline(always)]
|
||||
pub fn serialize_pretty<T, S>(value: &T,
|
||||
serializer: S)
|
||||
-> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
Ser::new_pretty(value).serialize(serializer)
|
||||
}
|
||||
|
||||
/// A wrapper to deserialize Hyper types.
|
||||
///
|
||||
/// This is useful with functions such as `serde_json::from_str`.
|
||||
///
|
||||
/// Values of this type can only be obtained through
|
||||
/// the `serde::Deserialize` trait.
|
||||
#[derive(Debug)]
|
||||
pub struct De<T> {
|
||||
v: T,
|
||||
}
|
||||
|
||||
impl<T> De<T> {
|
||||
fn new(v: T) -> Self {
|
||||
De { v: v }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> De<T>
|
||||
where De<T>: Deserialize<'de>,
|
||||
{
|
||||
/// Consumes this wrapper, returning the deserialized value.
|
||||
#[inline(always)]
|
||||
pub fn into_inner(self) -> T {
|
||||
self.v
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper to serialize Hyper types.
|
||||
///
|
||||
/// This is useful with functions such as `serde_json::to_string`.
|
||||
///
|
||||
/// Values of this type can only be passed to the `serde::Serialize` trait.
|
||||
#[derive(Debug)]
|
||||
pub struct Ser<'a, T: 'a> {
|
||||
v: &'a T,
|
||||
pretty: bool,
|
||||
}
|
||||
|
||||
impl<'a, T> Ser<'a, T>
|
||||
where Ser<'a, T>: serde::Serialize,
|
||||
{
|
||||
/// Returns a new `Ser` wrapper.
|
||||
#[inline(always)]
|
||||
pub fn new(value: &'a T) -> Self {
|
||||
Ser {
|
||||
v: value,
|
||||
pretty: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new `Ser` wrapper, in pretty mode.
|
||||
///
|
||||
/// See `serialize_pretty`.
|
||||
#[inline(always)]
|
||||
pub fn new_pretty(value: &'a T) -> Self {
|
||||
Ser {
|
||||
v: value,
|
||||
pretty: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenience wrapper to be used as a type parameter, for example when
|
||||
/// a `Vec<T>` need to be passed to serde.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Serde<T>(pub T)
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize;
|
||||
|
||||
impl<T> Serde<T>
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
/// Consumes this wrapper, returning the inner value.
|
||||
#[inline(always)]
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Serde<T>
|
||||
where T: fmt::Debug,
|
||||
for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
self.0.fmt(formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Serde<T>
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Serde<T>
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq<T> for Serde<T>
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.0 == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T> Deserialize<'b> for Serde<T>
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'b>,
|
||||
{
|
||||
De::deserialize(deserializer).map(De::into_inner).map(Serde)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Serde<T>
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
Ser::new(&self.0).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for De<ContentType> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
deserialize(deserializer).map(ContentType).map(De::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for Ser<'a, ContentType> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serialize(&self.v.0, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for De<Cookie<'static>> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
struct CookieVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for CookieVisitor {
|
||||
type Value = De<Cookie<'static>>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "an HTTP cookie header value")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
Cookie::parse(v)
|
||||
.map(Cookie::into_owned)
|
||||
.map(De::new)
|
||||
.map_err(|e| E::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_string(CookieVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'cookie> Serialize for Ser<'a, Cookie<'cookie>> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.v.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for De<Headers> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
struct HeadersVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for HeadersVisitor {
|
||||
type Value = De<Headers>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "a map from header names to header values")
|
||||
}
|
||||
|
||||
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
Ok(De::new(Headers::new()))
|
||||
}
|
||||
|
||||
fn visit_map<V>(self,
|
||||
mut visitor: V)
|
||||
-> Result<Self::Value, V::Error>
|
||||
where V: MapAccess<'de>,
|
||||
{
|
||||
let mut headers = Headers::new();
|
||||
while let Some((k, v)) = visitor.next_entry::<String, Value>()? {
|
||||
headers.set_raw(k, v.0);
|
||||
}
|
||||
Ok(De::new(headers))
|
||||
}
|
||||
}
|
||||
|
||||
struct Value(Vec<Vec<u8>>);
|
||||
|
||||
impl<'de> Deserialize<'de> for Value {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_seq(ValueVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct ValueVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ValueVisitor {
|
||||
type Value = Value;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "an array of strings and sequences of bytes")
|
||||
}
|
||||
|
||||
fn visit_unit<E>(self) -> Result<Value, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
Ok(Value(vec![]))
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error>
|
||||
where V: SeqAccess<'de>,
|
||||
{
|
||||
// Clamp to not OOM on rogue values.
|
||||
let capacity = cmp::min(visitor.size_hint().unwrap_or(0), 64);
|
||||
let mut values = Vec::with_capacity(capacity);
|
||||
while let Some(v) = visitor.next_element::<ByteBuf>()? {
|
||||
values.push(v.into());
|
||||
}
|
||||
Ok(Value(values))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_map(HeadersVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for Ser<'a, Headers> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
struct Value<'headers>(&'headers [Vec<u8>], bool);
|
||||
|
||||
impl<'headers> Serialize for Value<'headers> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
let mut serializer =
|
||||
serializer.serialize_seq(Some(self.0.len()))?;
|
||||
for v in self.0 {
|
||||
if self.1 {
|
||||
if let Ok(v) = str::from_utf8(v) {
|
||||
serializer.serialize_element(v)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
serializer.serialize_element(&Bytes::new(v))?;
|
||||
}
|
||||
serializer.end()
|
||||
}
|
||||
}
|
||||
|
||||
let mut serializer = serializer.serialize_map(Some(self.v.len()))?;
|
||||
for header in self.v.iter() {
|
||||
let name = header.name();
|
||||
let value = self.v.get_raw(name).unwrap();
|
||||
serializer.serialize_entry(name, &Value(value, self.pretty))?;
|
||||
}
|
||||
serializer.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for De<Method> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
struct MethodVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for MethodVisitor {
|
||||
type Value = De<Method>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "an HTTP method")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
v.parse::<Method>().map(De::new).map_err(E::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_string(MethodVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for Ser<'a, Method> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
Serialize::serialize(self.v.as_ref(), serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for De<Mime> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
struct MimeVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for MimeVisitor {
|
||||
type Value = De<Mime>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "a mime type")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
v.parse::<Mime>().map(De::new).map_err(|()| {
|
||||
E::custom("could not parse mime type")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_string(MimeVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for Ser<'a, Mime> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.v.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for De<RawStatus> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
let (code, reason) = Deserialize::deserialize(deserializer)?;
|
||||
Ok(De::new(RawStatus(code, reason)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for Ser<'a, RawStatus> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
(self.v.0, &self.v.1).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for De<Tm> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
struct TmVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for TmVisitor {
|
||||
type Value = De<Tm>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "a date and time according to RFC 3339")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
strptime(v, "%Y-%m-%dT%H:%M:%SZ").map(De::new).map_err(|e| {
|
||||
E::custom(e.to_string())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_string(TmVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for Ser<'a, Tm> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.v.rfc3339().to_string())
|
||||
}
|
||||
}
|
33
third_party/rust/hyper_serde/tests/supported.rs
vendored
Normal file
33
third_party/rust/hyper_serde/tests/supported.rs
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
extern crate cookie;
|
||||
extern crate hyper;
|
||||
extern crate hyper_serde;
|
||||
extern crate mime;
|
||||
extern crate serde;
|
||||
extern crate time;
|
||||
|
||||
use cookie::Cookie;
|
||||
use hyper::header::{ContentType, Headers};
|
||||
use hyper::http::RawStatus;
|
||||
use hyper::method::Method;
|
||||
use hyper_serde::{De, Ser, Serde};
|
||||
use mime::Mime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::Tm;
|
||||
|
||||
fn is_supported<T>()
|
||||
where for<'de> De<T>: Deserialize<'de>,
|
||||
for<'a> Ser<'a, T>: Serialize,
|
||||
for <'de> Serde<T>: Deserialize<'de> + Serialize
|
||||
{
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supported() {
|
||||
is_supported::<Cookie>();
|
||||
is_supported::<ContentType>();
|
||||
is_supported::<Headers>();
|
||||
is_supported::<Method>();
|
||||
is_supported::<Mime>();
|
||||
is_supported::<RawStatus>();
|
||||
is_supported::<Tm>();
|
||||
}
|
132
third_party/rust/hyper_serde/tests/tokens.rs
vendored
Normal file
132
third_party/rust/hyper_serde/tests/tokens.rs
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
extern crate cookie;
|
||||
extern crate hyper;
|
||||
extern crate hyper_serde;
|
||||
#[macro_use]
|
||||
extern crate mime;
|
||||
extern crate serde;
|
||||
extern crate serde_test;
|
||||
extern crate time;
|
||||
|
||||
use cookie::Cookie;
|
||||
use hyper::header::{ContentType, Headers};
|
||||
use hyper::http::RawStatus;
|
||||
use hyper::method::Method;
|
||||
use hyper_serde::{De, Ser, deserialize};
|
||||
use serde::Deserialize;
|
||||
use serde_test::{Deserializer, Token, assert_ser_tokens};
|
||||
use std::fmt::Debug;
|
||||
use time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_content_type() {
|
||||
let content_type = ContentType(mime!(Application / Json));
|
||||
let tokens = &[Token::Str("application/json")];
|
||||
|
||||
assert_ser_tokens(&Ser::new(&content_type), tokens);
|
||||
assert_de_tokens(&content_type, tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cookie() {
|
||||
let cookie = Cookie::build("Hello", "World!")
|
||||
.max_age(Duration::seconds(42))
|
||||
.domain("servo.org")
|
||||
.path("/")
|
||||
.secure(true)
|
||||
.http_only(false)
|
||||
.finish();
|
||||
|
||||
let tokens = &[Token::Str("Hello=World!; Secure; Path=/; \
|
||||
Domain=servo.org; Max-Age=42")];
|
||||
|
||||
assert_ser_tokens(&Ser::new(&cookie), tokens);
|
||||
assert_de_tokens(&cookie, tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_headers_empty() {
|
||||
let headers = Headers::new();
|
||||
|
||||
let tokens = &[Token::Map { len: Some(0) }, Token::MapEnd];
|
||||
|
||||
assert_ser_tokens(&Ser::new(&headers), tokens);
|
||||
assert_de_tokens(&headers, tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_headers_not_empty() {
|
||||
use hyper::header::Host;
|
||||
|
||||
let mut headers = Headers::new();
|
||||
headers.set(Host {
|
||||
hostname: "baguette".to_owned(),
|
||||
port: None,
|
||||
});
|
||||
|
||||
// In Hyper 0.9, Headers is internally a HashMap and thus testing this
|
||||
// with multiple headers is non-deterministic.
|
||||
|
||||
let tokens = &[Token::Map{ len: Some(1) },
|
||||
Token::Str("Host"),
|
||||
Token::Seq{ len: Some(1) },
|
||||
Token::Bytes(b"baguette"),
|
||||
Token::SeqEnd,
|
||||
Token::MapEnd];
|
||||
|
||||
assert_ser_tokens(&Ser::new(&headers), tokens);
|
||||
assert_de_tokens(&headers, tokens);
|
||||
|
||||
let pretty = &[Token::Map{ len: Some(1) },
|
||||
Token::Str("Host"),
|
||||
Token::Seq{ len: Some(1) },
|
||||
Token::Str("baguette"),
|
||||
Token::SeqEnd,
|
||||
Token::MapEnd];
|
||||
|
||||
assert_ser_tokens(&Ser::new_pretty(&headers), pretty);
|
||||
assert_de_tokens(&headers, pretty);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_method() {
|
||||
let method = Method::Put;
|
||||
let tokens = &[Token::Str("PUT")];
|
||||
|
||||
assert_ser_tokens(&Ser::new(&method), tokens);
|
||||
assert_de_tokens(&method, tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_status() {
|
||||
use std::borrow::Cow;
|
||||
|
||||
let raw_status = RawStatus(200, Cow::Borrowed("OK"));
|
||||
let tokens = &[Token::Tuple{ len: 2 },
|
||||
Token::U16(200),
|
||||
Token::Str("OK"),
|
||||
Token::TupleEnd];
|
||||
|
||||
assert_ser_tokens(&Ser::new(&raw_status), tokens);
|
||||
assert_de_tokens(&raw_status, tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tm() {
|
||||
use time::strptime;
|
||||
|
||||
let time = strptime("2017-02-22T12:03:31Z", "%Y-%m-%dT%H:%M:%SZ").unwrap();
|
||||
let tokens = &[Token::Str("2017-02-22T12:03:31Z")];
|
||||
|
||||
assert_ser_tokens(&Ser::new(&time), tokens);
|
||||
assert_de_tokens(&time, tokens);
|
||||
}
|
||||
|
||||
pub fn assert_de_tokens<T>(value: &T, tokens: &[Token])
|
||||
where T: Debug + PartialEq,
|
||||
for<'de> De<T>: Deserialize<'de>,
|
||||
{
|
||||
let mut deserializer = Deserializer::new(&tokens);
|
||||
let v = deserialize::<T, _>(&mut deserializer).unwrap();
|
||||
assert_eq!(&v, value);
|
||||
assert_eq!(deserializer.next_token_opt(), None);
|
||||
}
|
1
third_party/rust/serde_bytes/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/serde_bytes/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"acd21fe58d1af762230c1dec07b9e0131d65b1751f5e5d0aebb7cd6f79f56720","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"f0b7988c93ab594ca02b313b312b97a4c83669cd31aa0705711c113052130144","src/lib.rs":"cc5ff1cc84363022ac02e7291976b8d8d679cf5fbd021f192570c59e4011ddbd","src/value.rs":"911090aa5f4b0ee7ea00a8fe9d72e4df33dd4d9017689f0bdf97fa3a3d267817"},"package":"adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"}
|
41
third_party/rust/serde_bytes/Cargo.toml
vendored
Normal file
41
third_party/rust/serde_bytes/Cargo.toml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "serde_bytes"
|
||||
version = "0.10.4"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
description = "Optimized handling of `&[u8]` and `Vec<u8>` for Serde"
|
||||
homepage = "https://serde.rs"
|
||||
documentation = "https://docs.serde.rs/serde_bytes/"
|
||||
readme = "README.md"
|
||||
keywords = ["serde", "serialization", "no_std"]
|
||||
categories = ["encoding"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/serde-rs/bytes"
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
default-features = false
|
||||
[dev-dependencies.bincode]
|
||||
version = "0.8"
|
||||
|
||||
[dev-dependencies.serde_derive]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.serde_test]
|
||||
version = "1.0"
|
||||
|
||||
[features]
|
||||
alloc = ["serde/alloc"]
|
||||
default = ["std"]
|
||||
std = ["serde/std"]
|
201
third_party/rust/serde_bytes/LICENSE-APACHE
vendored
Normal file
201
third_party/rust/serde_bytes/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
25
third_party/rust/serde_bytes/LICENSE-MIT
vendored
Normal file
25
third_party/rust/serde_bytes/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) 2014 The Rust Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
55
third_party/rust/serde_bytes/README.md
vendored
Normal file
55
third_party/rust/serde_bytes/README.md
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
# serde\_bytes [![Build Status](https://api.travis-ci.org/serde-rs/bytes.svg?branch=master)](https://travis-ci.org/serde-rs/bytes) [![Latest Version](https://img.shields.io/crates/v/serde_bytes.svg)](https://crates.io/crates/serde_bytes)
|
||||
|
||||
Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
|
||||
|
||||
Without specialization, Rust forces Serde to treat `&[u8]` just like any
|
||||
other slice and `Vec<u8>` just like any other vector. In reality this
|
||||
particular slice and vector can often be serialized and deserialized in a
|
||||
more efficient, compact representation in many formats.
|
||||
|
||||
When working with such a format, you can opt into specialized handling of
|
||||
`&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec<u8>` by wrapping it
|
||||
in `serde_bytes::ByteBuf`.
|
||||
|
||||
This crate supports the Serde `with` attribute to enable efficient handling
|
||||
of `&[u8]` and `Vec<u8>` in structs without needing a wrapper type.
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate serde;
|
||||
extern crate serde_bytes;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Efficient<'a> {
|
||||
#[serde(with = "serde_bytes")]
|
||||
bytes: &'a [u8],
|
||||
|
||||
#[serde(with = "serde_bytes")]
|
||||
byte_buf: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Packet {
|
||||
#[serde(with = "serde_bytes")]
|
||||
payload: Vec<u8>,
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Serde is licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
431
third_party/rust/serde_bytes/src/lib.rs
vendored
Normal file
431
third_party/rust/serde_bytes/src/lib.rs
vendored
Normal file
@ -0,0 +1,431 @@
|
||||
//! Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
|
||||
//!
|
||||
//! Without specialization, Rust forces Serde to treat `&[u8]` just like any
|
||||
//! other slice and `Vec<u8>` just like any other vector. In reality this
|
||||
//! particular slice and vector can often be serialized and deserialized in a
|
||||
//! more efficient, compact representation in many formats.
|
||||
//!
|
||||
//! When working with such a format, you can opt into specialized handling of
|
||||
//! `&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec<u8>` by wrapping it
|
||||
//! in `serde_bytes::ByteBuf`.
|
||||
//!
|
||||
//! This crate supports the Serde `with` attribute to enable efficient handling
|
||||
//! of `&[u8]` and `Vec<u8>` in structs without needing a wrapper type.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #[macro_use]
|
||||
//! extern crate serde_derive;
|
||||
//!
|
||||
//! extern crate serde;
|
||||
//! extern crate serde_bytes;
|
||||
//!
|
||||
//! #[derive(Serialize)]
|
||||
//! struct Efficient<'a> {
|
||||
//! #[serde(with = "serde_bytes")]
|
||||
//! bytes: &'a [u8],
|
||||
//!
|
||||
//! #[serde(with = "serde_bytes")]
|
||||
//! byte_buf: Vec<u8>,
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Serialize, Deserialize)]
|
||||
//! struct Packet {
|
||||
//! #[serde(with = "serde_bytes")]
|
||||
//! payload: Vec<u8>,
|
||||
//! }
|
||||
//! #
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_bytes/0.10.4")]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::{fmt, ops};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core::{fmt, ops};
|
||||
|
||||
use self::fmt::Debug;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::Vec;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
use serde::de::{Deserialize, Deserializer, Visitor, Error};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub use self::bytebuf::ByteBuf;
|
||||
|
||||
mod value;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Serde `serialize_with` function to serialize bytes efficiently.
|
||||
///
|
||||
/// This function can be used with either of the following Serde attributes:
|
||||
///
|
||||
/// - `#[serde(with = "serde_bytes")]`
|
||||
/// - `#[serde(serialize_with = "serde_bytes::serialize")]`
|
||||
///
|
||||
/// ```rust
|
||||
/// #[macro_use]
|
||||
/// extern crate serde_derive;
|
||||
///
|
||||
/// extern crate serde;
|
||||
/// extern crate serde_bytes;
|
||||
///
|
||||
/// #[derive(Serialize)]
|
||||
/// struct Efficient<'a> {
|
||||
/// #[serde(with = "serde_bytes")]
|
||||
/// bytes: &'a [u8],
|
||||
///
|
||||
/// #[serde(with = "serde_bytes")]
|
||||
/// byte_buf: Vec<u8>,
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
pub fn serialize<T, S>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where T: ?Sized + AsRef<[u8]>,
|
||||
S: Serializer
|
||||
{
|
||||
serializer.serialize_bytes(bytes.as_ref())
|
||||
}
|
||||
|
||||
/// Serde `deserialize_with` function to deserialize bytes efficiently.
|
||||
///
|
||||
/// This function can be used with either of the following Serde attributes:
|
||||
///
|
||||
/// - `#[serde(with = "serde_bytes")]`
|
||||
/// - `#[serde(deserialize_with = "serde_bytes::deserialize")]`
|
||||
///
|
||||
/// ```rust
|
||||
/// #[macro_use]
|
||||
/// extern crate serde_derive;
|
||||
///
|
||||
/// extern crate serde;
|
||||
/// extern crate serde_bytes;
|
||||
///
|
||||
/// #[derive(Deserialize)]
|
||||
/// struct Packet {
|
||||
/// #[serde(with = "serde_bytes")]
|
||||
/// payload: Vec<u8>,
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||
where T: From<Vec<u8>>,
|
||||
D: Deserializer<'de>
|
||||
{
|
||||
ByteBuf::deserialize(deserializer).map(|buf| Into::<Vec<u8>>::into(buf).into())
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Wrapper around `&[u8]` to serialize and deserialize efficiently.
|
||||
///
|
||||
/// ```rust
|
||||
/// extern crate bincode;
|
||||
/// extern crate serde_bytes;
|
||||
///
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::io;
|
||||
///
|
||||
/// use serde_bytes::Bytes;
|
||||
///
|
||||
/// fn print_encoded_cache() -> Result<(), bincode::Error> {
|
||||
/// let mut cache = HashMap::new();
|
||||
/// cache.insert(3, Bytes::new(b"three"));
|
||||
/// cache.insert(2, Bytes::new(b"two"));
|
||||
/// cache.insert(1, Bytes::new(b"one"));
|
||||
///
|
||||
/// bincode::serialize_into(&mut io::stdout(), &cache, bincode::Infinite)
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # print_encoded_cache().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Bytes<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Bytes<'a> {
|
||||
/// Wrap an existing `&[u8]`.
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Bytes { bytes: bytes }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(self.bytes, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for Bytes<'a> {
|
||||
fn from(bytes: &'a [u8]) -> Self {
|
||||
Bytes::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Bytes<'a>> for &'a [u8] {
|
||||
fn from(wrapper: Bytes<'a>) -> &'a [u8] {
|
||||
wrapper.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::Deref for Bytes<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for Bytes<'a> {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
struct BytesVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for BytesVisitor {
|
||||
type Value = Bytes<'de>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a borrowed byte array")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Bytes<'de>, E>
|
||||
where E: Error
|
||||
{
|
||||
Ok(Bytes::from(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Bytes<'de>, E>
|
||||
where E: Error
|
||||
{
|
||||
Ok(Bytes::from(v.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'de: 'a> Deserialize<'de> for Bytes<'a> {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Bytes<'a>, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
deserializer.deserialize_bytes(BytesVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
mod bytebuf {
|
||||
#[cfg(feature = "std")]
|
||||
use std::{cmp, fmt, ops};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core::{cmp, fmt, ops};
|
||||
|
||||
use self::fmt::Debug;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::{String, Vec};
|
||||
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error};
|
||||
|
||||
/// Wrapper around `Vec<u8>` to serialize and deserialize efficiently.
|
||||
///
|
||||
/// ```rust
|
||||
/// extern crate bincode;
|
||||
/// extern crate serde_bytes;
|
||||
///
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::io;
|
||||
///
|
||||
/// use serde_bytes::ByteBuf;
|
||||
///
|
||||
/// fn deserialize_bytebufs() -> Result<(), bincode::Error> {
|
||||
/// let example_data = [
|
||||
/// 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 116,
|
||||
/// 119, 111, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 111, 110, 101];
|
||||
///
|
||||
/// let map: HashMap<u32, ByteBuf> =
|
||||
/// bincode::deserialize_from(&mut &example_data[..], bincode::Infinite)?;
|
||||
///
|
||||
/// println!("{:?}", map);
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # deserialize_bytebufs().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ByteBuf {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ByteBuf {
|
||||
/// Construct a new, empty `ByteBuf`.
|
||||
pub fn new() -> Self {
|
||||
ByteBuf::from(Vec::new())
|
||||
}
|
||||
|
||||
/// Construct a new, empty `ByteBuf` with the specified capacity.
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
ByteBuf::from(Vec::with_capacity(cap))
|
||||
}
|
||||
|
||||
/// Wrap existing bytes in a `ByteBuf`.
|
||||
pub fn from<T: Into<Vec<u8>>>(bytes: T) -> Self {
|
||||
ByteBuf { bytes: bytes.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for ByteBuf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(&self.bytes, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteBuf> for Vec<u8> {
|
||||
fn from(wrapper: ByteBuf) -> Vec<u8> {
|
||||
wrapper.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for ByteBuf {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
ByteBuf::from(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Vec<u8>> for ByteBuf {
|
||||
fn as_ref(&self) -> &Vec<u8> {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for ByteBuf {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Vec<u8>> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut Vec<u8> {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for ByteBuf {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.bytes[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::DerefMut for ByteBuf {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ByteBuf {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
serializer.serialize_bytes(&self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
struct ByteBufVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ByteBufVisitor {
|
||||
type Value = ByteBuf;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("byte array")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<ByteBuf, V::Error>
|
||||
where V: SeqAccess<'de>
|
||||
{
|
||||
let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096);
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
while let Some(value) = try!(visitor.next_element()) {
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(ByteBuf::from(values))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<ByteBuf, E>
|
||||
where E: Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<ByteBuf, E>
|
||||
where E: Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, v: &str) -> Result<ByteBuf, E>
|
||||
where E: Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_string<E>(self, v: String) -> Result<ByteBuf, E>
|
||||
where E: Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteBuf {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteBuf, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
deserializer.deserialize_byte_buf(ByteBufVisitor)
|
||||
}
|
||||
}
|
||||
}
|
91
third_party/rust/serde_bytes/src/value.rs
vendored
Normal file
91
third_party/rust/serde_bytes/src/value.rs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
use serde::de::{Deserializer, IntoDeserializer, Visitor, Error};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::Vec;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for super::Bytes<'a>
|
||||
where E: Error
|
||||
{
|
||||
type Deserializer = BytesDeserializer<'a, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
BytesDeserializer {
|
||||
value: self.into(),
|
||||
error: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A deserializer that deserializes a `&[u8]`.
|
||||
pub struct BytesDeserializer<'a, E> {
|
||||
value: &'a [u8],
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
|
||||
where E: Error
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor<'de>
|
||||
{
|
||||
visitor.visit_bytes(self.value)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct enum identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for super::ByteBuf
|
||||
where E: Error
|
||||
{
|
||||
type Deserializer = ByteBufDeserializer<E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
ByteBufDeserializer {
|
||||
value: self.into(),
|
||||
error: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A deserializer that deserializes a `Vec<u8>`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub struct ByteBufDeserializer<E> {
|
||||
value: Vec<u8>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, E> Deserializer<'de> for ByteBufDeserializer<E>
|
||||
where E: Error
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor<'de>
|
||||
{
|
||||
visitor.visit_byte_buf(self.value)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct enum identifier ignored_any
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user