зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
4b2243fe17
|
@ -558,14 +558,6 @@ dependencies = [
|
|||
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "debug_unreachable"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.11"
|
||||
|
@ -1015,7 +1007,7 @@ dependencies = [
|
|||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.58 (git+https://github.com/servo/serde?branch=deserialize_from_enums7)",
|
||||
"string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1041,7 +1033,7 @@ dependencies = [
|
|||
"petgraph 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1363,6 +1355,23 @@ dependencies = [
|
|||
"nsstring 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new-ordered-float"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.12"
|
||||
|
@ -1442,15 +1451,6 @@ dependencies = [
|
|||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordermap"
|
||||
version = "0.3.5"
|
||||
|
@ -1864,11 +1864,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.7.1"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1909,7 +1909,6 @@ dependencies = [
|
|||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fallible 0.0.1",
|
||||
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1922,11 +1921,12 @@ dependencies = [
|
|||
"malloc_size_of 0.0.1",
|
||||
"malloc_size_of_derive 0.0.1",
|
||||
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new-ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nsstring 0.1.0",
|
||||
"num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2216,14 +2216,6 @@ name = "unicode-xid"
|
|||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
|
@ -2553,7 +2545,6 @@ dependencies = [
|
|||
"checksum darling 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3effd06d4057f275cb7858889f4952920bab78dd8ff0f6e7dfe0c8d2e67ed89"
|
||||
"checksum darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "167dd3e235c2f1da16a635c282630452cdf49191eb05711de1bcd1d3d5068c00"
|
||||
"checksum darling_macro 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c53edaba455f6073a10c27c72440860eb3f60444f8c8660a391032eeae744d82"
|
||||
"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
|
||||
"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
|
||||
"checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
|
@ -2623,6 +2614,8 @@ dependencies = [
|
|||
"checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
|
||||
"checksum msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "65ba9d75bcea84e07812618fedf284a64776c2f2ea0cad6bca7f69739695a958"
|
||||
"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
|
||||
"checksum new-ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8ccbebba6fb53a6d2bdcfaf79cb339bc136dee3bfff54dc337a334bafe36476a"
|
||||
"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
|
||||
"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525"
|
||||
|
@ -2631,7 +2624,6 @@ dependencies = [
|
|||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
"checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10"
|
||||
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
|
||||
"checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
|
||||
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd"
|
||||
|
@ -2681,7 +2673,7 @@ dependencies = [
|
|||
"checksum smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c63726029f0069f88467873e47f392575f28f9f16b72ac65465263db4b3a13c"
|
||||
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
|
||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||
"checksum string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39cb4173bcbd1319da31faa5468a7e3870683d7a237150b0b0aaafd546f6ad12"
|
||||
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
|
||||
"checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
|
||||
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
|
||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||
|
@ -2710,7 +2702,6 @@ dependencies = [
|
|||
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
|
|
|
@ -4,16 +4,24 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
|
||||
const {
|
||||
UPDATE_SHOW_GRID_AREAS,
|
||||
UPDATE_SHOW_GRID_LINE_NUMBERS,
|
||||
UPDATE_SHOW_INFINITE_LINES
|
||||
} = require("../actions/index");
|
||||
|
||||
const INITIAL_HIGHLIGHTER_SETTINGS = {
|
||||
showGridAreasOverlay: false,
|
||||
showGridLineNumbers: false,
|
||||
showInfiniteLines: false,
|
||||
const SHOW_GRID_AREAS = "devtools.gridinspector.showGridAreas";
|
||||
const SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
|
||||
const SHOW_INFINITE_LINES = "devtools.gridinspector.showInfiniteLines";
|
||||
|
||||
const INITIAL_HIGHLIGHTER_SETTINGS = () => {
|
||||
return {
|
||||
showGridAreasOverlay: Services.prefs.getBoolPref(SHOW_GRID_AREAS),
|
||||
showGridLineNumbers: Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS),
|
||||
showInfiniteLines: Services.prefs.getBoolPref(SHOW_INFINITE_LINES),
|
||||
};
|
||||
};
|
||||
|
||||
const reducers = {
|
||||
|
@ -38,7 +46,7 @@ const reducers = {
|
|||
|
||||
};
|
||||
|
||||
module.exports = function(highlighterSettings = INITIAL_HIGHLIGHTER_SETTINGS, action) {
|
||||
module.exports = function(highlighterSettings = INITIAL_HIGHLIGHTER_SETTINGS(), action) {
|
||||
const reducer = reducers[action.type];
|
||||
if (!reducer) {
|
||||
return highlighterSettings;
|
||||
|
|
|
@ -6,23 +6,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {
|
||||
VIEW_NODE_VALUE_TYPE,
|
||||
VIEW_NODE_SHAPE_POINT_TYPE
|
||||
} = require("devtools/client/inspector/shared/node-types");
|
||||
|
||||
const {
|
||||
updateShowGridAreas,
|
||||
updateShowGridLineNumbers,
|
||||
updateShowInfiniteLines,
|
||||
} = require("devtools/client/inspector/grids/actions/highlighter-settings");
|
||||
|
||||
const DEFAULT_GRID_COLOR = "#4B0082";
|
||||
const SHOW_GRID_AREAS = "devtools.gridinspector.showGridAreas";
|
||||
const SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
|
||||
const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
|
||||
|
||||
/**
|
||||
* Highlighters overlay is a singleton managing all highlighters in the Inspector.
|
||||
|
@ -87,8 +77,6 @@ class HighlightersOverlay {
|
|||
this.inspector.on("markupmutation", this.onMarkupMutation);
|
||||
this.inspector.target.on("will-navigate", this.onWillNavigate);
|
||||
|
||||
this.loadGridHighlighterSettings();
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
|
@ -132,21 +120,6 @@ class HighlightersOverlay {
|
|||
el.removeEventListener("mouseout", this.onMouseOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the grid highligher display settings into the store from the stored preferences.
|
||||
*/
|
||||
loadGridHighlighterSettings() {
|
||||
const { dispatch } = this.inspector.store;
|
||||
|
||||
const showGridAreas = Services.prefs.getBoolPref(SHOW_GRID_AREAS);
|
||||
const showGridLineNumbers = Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS);
|
||||
const showInfinteLines = Services.prefs.getBoolPref(SHOW_INFINITE_LINES_PREF);
|
||||
|
||||
dispatch(updateShowGridAreas(showGridAreas));
|
||||
dispatch(updateShowGridLineNumbers(showGridLineNumbers));
|
||||
dispatch(updateShowInfiniteLines(showInfinteLines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the shapes highlighter for the given node.
|
||||
|
||||
|
|
|
@ -1281,7 +1281,9 @@ FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless,
|
|||
if (!aDeadline.IsNull()) {
|
||||
if (aDeadline < now) {
|
||||
// This slice overflowed the idle period.
|
||||
idleDuration = aDeadline - startTimeStamp;
|
||||
if (aDeadline > startTimeStamp) {
|
||||
idleDuration = aDeadline - startTimeStamp;
|
||||
}
|
||||
} else {
|
||||
idleDuration = duration;
|
||||
}
|
||||
|
|
|
@ -52,9 +52,10 @@ ParentLayerCoord GetCurrentSpan(const MultiTouchInput& aEvent)
|
|||
return delta.Length();
|
||||
}
|
||||
|
||||
ParentLayerCoord GestureEventListener::GetYSpanFromStartPoint()
|
||||
ParentLayerCoord GestureEventListener::GetYSpanFromGestureStartPoint()
|
||||
{
|
||||
const ParentLayerPoint start = mTouchStartPosition;
|
||||
// use the position that began the one-touch-pinch gesture rather mTouchStartPosition
|
||||
const ParentLayerPoint start = mOneTouchPinchStartPosition;
|
||||
const ParentLayerPoint& current = mTouches[0].mLocalScreenPoint;
|
||||
return current.y - start.y;
|
||||
}
|
||||
|
@ -313,6 +314,9 @@ nsEventStatus GestureEventListener::HandleInputTouchMove()
|
|||
ParentLayerCoord currentSpan = 1.0f;
|
||||
ParentLayerPoint currentFocus = mTouchStartPosition;
|
||||
|
||||
// save the position that the one-touch-pinch gesture actually begins
|
||||
mOneTouchPinchStartPosition = mLastTouchInput.mTouches[0].mLocalScreenPoint;
|
||||
|
||||
PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START,
|
||||
mLastTouchInput.mTime,
|
||||
mLastTouchInput.mTimeStamp,
|
||||
|
@ -388,7 +392,7 @@ nsEventStatus GestureEventListener::HandleInputTouchMove()
|
|||
}
|
||||
|
||||
case GESTURE_ONE_TOUCH_PINCH: {
|
||||
ParentLayerCoord currentSpan = GetYSpanFromStartPoint();
|
||||
ParentLayerCoord currentSpan = GetYSpanFromGestureStartPoint();
|
||||
float effectiveSpan = 1.0f + (fabsf(currentSpan.value) * ONE_TOUCH_PINCH_SPEED);
|
||||
ParentLayerPoint currentFocus = mTouchStartPosition;
|
||||
|
||||
|
|
|
@ -150,10 +150,10 @@ private:
|
|||
bool SecondTapIsFar() const;
|
||||
|
||||
/**
|
||||
* Returns current vertical span, counting from the where the user first put
|
||||
* her finger down.
|
||||
* Returns current vertical span, counting from the where the gesture first
|
||||
* began (after a brief delay detecting the gesture from first touch).
|
||||
*/
|
||||
ParentLayerCoord GetYSpanFromStartPoint();
|
||||
ParentLayerCoord GetYSpanFromGestureStartPoint();
|
||||
|
||||
/**
|
||||
* Do actual state transition and reset substates.
|
||||
|
@ -208,6 +208,16 @@ private:
|
|||
*/
|
||||
MultiTouchInput mLastTapInput;
|
||||
|
||||
/**
|
||||
* Position of the last touch that exceeds the GetTouchStartTolerance when
|
||||
* performing a one-touch-pinch gesture; using the mTouchStartPosition is
|
||||
* slightly inaccurate because by the time the touch position has passed
|
||||
* the threshold for the gesture, there is already a span that the zoom
|
||||
* is calculated from, instead of starting at 1.0 when the threshold gets
|
||||
* passed.
|
||||
*/
|
||||
ParentLayerPoint mOneTouchPinchStartPosition;
|
||||
|
||||
/**
|
||||
* Position of the last touch starting. This is only valid during an attempt
|
||||
* to determine if a touch is a tap. If a touch point moves away from
|
||||
|
|
|
@ -590,7 +590,9 @@ LoadInfoToParentLoadInfoForwarder(nsILoadInfo* aLoadInfo,
|
|||
ParentLoadInfoForwarderArgs* aForwarderArgsOut)
|
||||
{
|
||||
if (!aLoadInfo) {
|
||||
*aForwarderArgsOut = ParentLoadInfoForwarderArgs(false, void_t());
|
||||
*aForwarderArgsOut = ParentLoadInfoForwarderArgs(false, void_t(),
|
||||
nsILoadInfo::TAINTING_BASIC,
|
||||
false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -600,9 +602,14 @@ LoadInfoToParentLoadInfoForwarder(nsILoadInfo* aLoadInfo,
|
|||
ipcController = controller.ref().ToIPC();
|
||||
}
|
||||
|
||||
uint32_t tainting = nsILoadInfo::TAINTING_BASIC;
|
||||
Unused << aLoadInfo->GetTainting(&tainting);
|
||||
|
||||
*aForwarderArgsOut = ParentLoadInfoForwarderArgs(
|
||||
aLoadInfo->GetAllowInsecureRedirectToDataURI(),
|
||||
ipcController
|
||||
ipcController,
|
||||
tainting,
|
||||
aLoadInfo->GetServiceWorkerTaintingSynthesized()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -627,6 +634,13 @@ MergeParentLoadInfoForwarder(ParentLoadInfoForwarderArgs const& aForwarderArgs,
|
|||
ServiceWorkerDescriptor(controller.get_IPCServiceWorkerDescriptor()));
|
||||
}
|
||||
|
||||
if (aForwarderArgs.serviceWorkerTaintingSynthesized()) {
|
||||
aLoadInfo->SynthesizeServiceWorkerTainting(
|
||||
static_cast<LoadTainting>(aForwarderArgs.tainting()));
|
||||
} else {
|
||||
aLoadInfo->MaybeIncreaseTainting(aForwarderArgs.tainting());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -3595,6 +3595,7 @@ WorkerMain(void* arg)
|
|||
|
||||
sc->isWorker = true;
|
||||
JS_SetContextPrivate(cx, sc);
|
||||
JS_SetGrayGCRootsTracer(cx, TraceGrayRoots, nullptr);
|
||||
SetWorkerContextOptions(cx);
|
||||
JS::SetBuildIdOp(cx, ShellBuildId);
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
var BUGNUMBER = 1466387;
|
||||
var summary = 'grayRoot() testing on worker thread';
|
||||
|
||||
// Before bug 1466387, the gray root tracer was not set up on worker threads,
|
||||
// but the grayRoot() function was still available. This resulted in a GC
|
||||
// collecting the gray root, then a read barrier firing on the dead object.
|
||||
//
|
||||
// This is a crashtest. If it does not crash, it will throw a ReferenceError,
|
||||
// but that's ok.
|
||||
|
||||
print('BUGNUMBER: ' + BUGNUMBER);
|
||||
print("STATUS: " + summary);
|
||||
|
||||
if (typeof 'evalInWorder' == 'function') {
|
||||
evalInWorker(`
|
||||
var wm = new WeakMap();
|
||||
grayRoot().map = wm;
|
||||
gczeal(4,10);
|
||||
evaluate(\`
|
||||
grayRoot().map = __v_1173;
|
||||
if (!class i { constructor() { } } ()) {
|
||||
(function __f_252( get , ) {})();
|
||||
}
|
||||
\`);
|
||||
`);
|
||||
}
|
||||
|
||||
this.reportCompare && reportCompare(true, true, summary);
|
|
@ -5,23 +5,22 @@
|
|||
|
||||
package org.mozilla.gecko.notifications;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.GeckoActivityMonitor;
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoService;
|
||||
import org.mozilla.gecko.NotificationListener;
|
||||
|
@ -299,13 +298,23 @@ public final class NotificationClient implements NotificationListener {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void setForegroundNotificationLocked(final String name,
|
||||
final Notification notification) {
|
||||
@SuppressLint("NewApi")
|
||||
private void setForegroundNotificationLocked(@NonNull final String name,
|
||||
@NonNull final Notification notification) {
|
||||
mForegroundNotification = name;
|
||||
|
||||
final Intent intent = new Intent(mContext, NotificationService.class);
|
||||
intent.putExtra(NotificationService.EXTRA_NOTIFICATION, notification);
|
||||
mContext.startService(intent);
|
||||
if (AppConstants.Versions.preO) {
|
||||
mContext.startService(intent);
|
||||
} else {
|
||||
mContext.startForegroundService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeForegroundNotificationLocked() {
|
||||
mForegroundNotification = null;
|
||||
mContext.stopService(new Intent(mContext, NotificationService.class));
|
||||
}
|
||||
|
||||
private void updateForegroundNotificationLocked(final String oldName) {
|
||||
|
@ -328,6 +337,6 @@ public final class NotificationClient implements NotificationListener {
|
|||
}
|
||||
}
|
||||
|
||||
setForegroundNotificationLocked(null, null);
|
||||
removeForegroundNotificationLocked();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,8 @@ public final class NotificationService extends Service {
|
|||
@Override // Service
|
||||
public int onStartCommand(final Intent intent, final int flags, final int startId) {
|
||||
final Notification notification = intent.getParcelableExtra(EXTRA_NOTIFICATION);
|
||||
if (notification != null) {
|
||||
// Start foreground notification.
|
||||
startForeground(R.id.foregroundNotification, notification);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
// Stop foreground notification
|
||||
stopForeground(true);
|
||||
stopSelfResult(startId);
|
||||
// Start foreground notification.
|
||||
startForeground(R.id.foregroundNotification, notification);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
|
|
|
@ -993,12 +993,13 @@ interface nsILoadInfo : nsISupports
|
|||
[noscript, nostdcall, notxpcom]
|
||||
PerformanceStoragePtr GetPerformanceStorage();
|
||||
|
||||
/* The service worker and fetch specifications require returning the
|
||||
* exact tainting level of the Response passed to FetchEvent.respondWith().
|
||||
* This method allows us to override the tainting level in that case.
|
||||
*
|
||||
* NOTE: This should not be used outside of service worker code! Use
|
||||
* nsILoadInfo::MaybeIncreaseTainting() instead.
|
||||
/**
|
||||
* The service worker and fetch specifications require returning the
|
||||
* exact tainting level of the Response passed to FetchEvent.respondWith().
|
||||
* This method allows us to override the tainting level in that case.
|
||||
*
|
||||
* NOTE: This should not be used outside of service worker code! Use
|
||||
* nsILoadInfo::MaybeIncreaseTainting() instead.
|
||||
*/
|
||||
[noscript, nostdcall, notxpcom]
|
||||
void SynthesizeServiceWorkerTainting(in LoadTainting aTainting);
|
||||
|
|
|
@ -132,6 +132,14 @@ struct ParentLoadInfoForwarderArgs
|
|||
// interception occurs.
|
||||
OptionalIPCServiceWorkerDescriptor controller;
|
||||
|
||||
// The service worker may synthesize a Response with a particular
|
||||
// tainting value.
|
||||
uint32_t tainting;
|
||||
|
||||
// We must also note that the tainting value was explicitly set
|
||||
// by the service worker.
|
||||
bool serviceWorkerTaintingSynthesized;
|
||||
|
||||
// IMPORTANT: when you add new properites here you must also update
|
||||
// LoadInfoToParentLoadInfoForwarder and MergeParentLoadInfoForwarder
|
||||
// in BackgroundUtils.cpp/.h!
|
||||
|
|
|
@ -1 +1 @@
|
|||
8232a58332dd
|
||||
30a4b03cd9d1
|
||||
|
|
|
@ -8,8 +8,8 @@ MAINTAINER Franziskus Kiefer <franziskuskiefer@gmail.com>
|
|||
ENV haclrepo https://github.com/mitls/hacl-star.git
|
||||
|
||||
# Define versions of dependencies
|
||||
ENV opamv 4.04.2
|
||||
ENV haclversion e13326efee1a9910004dccbb56f3d7be6639e0b8
|
||||
ENV opamv 4.05.0
|
||||
ENV haclversion 1da331f9ef30e13269e45ae73bbe4a4bca679ae6
|
||||
|
||||
# Install required packages and set versions
|
||||
ADD setup.sh /tmp/setup.sh
|
||||
|
|
|
@ -178,7 +178,7 @@ loser:
|
|||
SECKEY_DestroyPrivateKey(privKey);
|
||||
}
|
||||
if (data) {
|
||||
PORT_Free(data);
|
||||
PR_Free(data);
|
||||
}
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
|
||||
|
|
|
@ -10,4 +10,3 @@
|
|||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ CPPSRCS = \
|
|||
ssl_loopback_unittest.cc \
|
||||
ssl_misc_unittest.cc \
|
||||
ssl_record_unittest.cc \
|
||||
ssl_recordsize_unittest.cc \
|
||||
ssl_resumption_unittest.cc \
|
||||
ssl_renegotiation_unittest.cc \
|
||||
ssl_skip_unittest.cc \
|
||||
|
|
|
@ -68,6 +68,7 @@ static const uint16_t kManyExtensions[] = {
|
|||
ssl_next_proto_nego_xtn,
|
||||
ssl_renegotiation_info_xtn,
|
||||
ssl_tls13_short_header_xtn,
|
||||
ssl_record_size_limit_xtn,
|
||||
1,
|
||||
0xffff};
|
||||
// The list here includes all extensions we expect to use (SSL_MAX_EXTENSIONS),
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
'ssl_loopback_unittest.cc',
|
||||
'ssl_misc_unittest.cc',
|
||||
'ssl_record_unittest.cc',
|
||||
'ssl_recordsize_unittest.cc',
|
||||
'ssl_resumption_unittest.cc',
|
||||
'ssl_renegotiation_unittest.cc',
|
||||
'ssl_skip_unittest.cc',
|
||||
|
|
|
@ -104,15 +104,13 @@ TEST_P(TlsPaddingTest, LastByteOfPadWrong) {
|
|||
class RecordReplacer : public TlsRecordFilter {
|
||||
public:
|
||||
RecordReplacer(const std::shared_ptr<TlsAgent>& a, size_t size)
|
||||
: TlsRecordFilter(a), enabled_(false), size_(size) {}
|
||||
: TlsRecordFilter(a), size_(size) {
|
||||
Disable();
|
||||
}
|
||||
|
||||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& data,
|
||||
DataBuffer* changed) override {
|
||||
if (!enabled_) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
EXPECT_EQ(kTlsApplicationDataType, header.content_type());
|
||||
changed->Allocate(size_);
|
||||
|
||||
|
@ -120,17 +118,33 @@ class RecordReplacer : public TlsRecordFilter {
|
|||
changed->data()[i] = i & 0xff;
|
||||
}
|
||||
|
||||
enabled_ = false;
|
||||
Disable();
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
void Enable() { enabled_ = true; }
|
||||
|
||||
private:
|
||||
bool enabled_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
TEST_P(TlsConnectStream, BadRecordMac) {
|
||||
EnsureTlsSetup();
|
||||
Connect();
|
||||
client_->SetFilter(std::make_shared<TlsRecordLastByteDamager>(client_));
|
||||
ExpectAlert(server_, kTlsAlertBadRecordMac);
|
||||
client_->SendData(10);
|
||||
|
||||
// Read from the client, get error.
|
||||
uint8_t buf[10];
|
||||
PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
|
||||
EXPECT_GT(0, rv);
|
||||
EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, PORT_GetError());
|
||||
|
||||
// Read the server alert.
|
||||
rv = PR_Read(client_->ssl_fd(), buf, sizeof(buf));
|
||||
EXPECT_GT(0, rv);
|
||||
EXPECT_EQ(SSL_ERROR_BAD_MAC_ALERT, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, LargeRecord) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
|
|
|
@ -0,0 +1,431 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
#include "gtest_utils.h"
|
||||
#include "scoped_ptrs.h"
|
||||
#include "tls_connect.h"
|
||||
#include "tls_filter.h"
|
||||
#include "tls_parser.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// This class tracks the maximum size of record that was sent, both cleartext
|
||||
// and plain. It only tracks records that have an outer type of
|
||||
// application_data. In TLS 1.3, this includes handshake messages.
|
||||
class TlsRecordMaximum : public TlsRecordFilter {
|
||||
public:
|
||||
TlsRecordMaximum(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsRecordFilter(a), max_ciphertext_(0), max_plaintext_(0) {}
|
||||
|
||||
size_t max_ciphertext() const { return max_ciphertext_; }
|
||||
size_t max_plaintext() const { return max_plaintext_; }
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& record, size_t* offset,
|
||||
DataBuffer* output) override {
|
||||
std::cerr << "max: " << record << std::endl;
|
||||
// Ignore unprotected packets.
|
||||
if (header.content_type() != kTlsApplicationDataType) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
max_ciphertext_ = (std::max)(max_ciphertext_, record.len());
|
||||
return TlsRecordFilter::FilterRecord(header, record, offset, output);
|
||||
}
|
||||
|
||||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& data,
|
||||
DataBuffer* changed) override {
|
||||
max_plaintext_ = (std::max)(max_plaintext_, data.len());
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t max_ciphertext_;
|
||||
size_t max_plaintext_;
|
||||
};
|
||||
|
||||
void CheckRecordSizes(const std::shared_ptr<TlsAgent>& agent,
|
||||
const std::shared_ptr<TlsRecordMaximum>& record_max,
|
||||
size_t config) {
|
||||
uint16_t cipher_suite;
|
||||
ASSERT_TRUE(agent->cipher_suite(&cipher_suite));
|
||||
|
||||
size_t expansion;
|
||||
size_t iv;
|
||||
switch (cipher_suite) {
|
||||
case TLS_AES_128_GCM_SHA256:
|
||||
case TLS_AES_256_GCM_SHA384:
|
||||
case TLS_CHACHA20_POLY1305_SHA256:
|
||||
expansion = 16;
|
||||
iv = 0;
|
||||
break;
|
||||
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
|
||||
expansion = 16;
|
||||
iv = 8;
|
||||
break;
|
||||
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
|
||||
// Expansion is 20 for the MAC. Maximum block padding is 16. Maximum
|
||||
// padding is added when the input plus the MAC is an exact multiple of
|
||||
// the block size.
|
||||
expansion = 20 + 16 - ((config + 20) % 16);
|
||||
iv = 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
ADD_FAILURE() << "No expansion set for ciphersuite "
|
||||
<< agent->cipher_suite_name();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (agent->version()) {
|
||||
case SSL_LIBRARY_VERSION_TLS_1_3:
|
||||
EXPECT_EQ(0U, iv) << "No IV for TLS 1.3";
|
||||
// We only have decryption in TLS 1.3.
|
||||
EXPECT_EQ(config - 1, record_max->max_plaintext())
|
||||
<< "bad plaintext length for " << agent->role_str();
|
||||
break;
|
||||
|
||||
case SSL_LIBRARY_VERSION_TLS_1_2:
|
||||
case SSL_LIBRARY_VERSION_TLS_1_1:
|
||||
expansion += iv;
|
||||
break;
|
||||
|
||||
case SSL_LIBRARY_VERSION_TLS_1_0:
|
||||
break;
|
||||
|
||||
default:
|
||||
ADD_FAILURE() << "Unexpected version " << agent->version();
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_EQ(config + expansion, record_max->max_ciphertext())
|
||||
<< "bad ciphertext length for " << agent->role_str();
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeMaximum) {
|
||||
uint16_t max_record_size =
|
||||
(version_ >= SSL_LIBRARY_VERSION_TLS_1_3) ? 16385 : 16384;
|
||||
size_t send_size = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3)
|
||||
? max_record_size
|
||||
: max_record_size + 1;
|
||||
|
||||
EnsureTlsSetup();
|
||||
auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
|
||||
client_max->EnableDecryption();
|
||||
auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
|
||||
server_max->EnableDecryption();
|
||||
|
||||
Connect();
|
||||
client_->SendData(send_size, send_size);
|
||||
server_->SendData(send_size, send_size);
|
||||
server_->ReadBytes(send_size);
|
||||
client_->ReadBytes(send_size);
|
||||
|
||||
CheckRecordSizes(client_, client_max, max_record_size);
|
||||
CheckRecordSizes(server_, server_max, max_record_size);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeMinimumClient) {
|
||||
EnsureTlsSetup();
|
||||
auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
|
||||
server_max->EnableDecryption();
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
SendReceive(127); // Big enough for one record, allowing for 1+N splitting.
|
||||
|
||||
CheckRecordSizes(server_, server_max, 64);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeMinimumServer) {
|
||||
EnsureTlsSetup();
|
||||
auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
|
||||
client_max->EnableDecryption();
|
||||
|
||||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
SendReceive(127);
|
||||
|
||||
CheckRecordSizes(client_, client_max, 64);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeAsymmetric) {
|
||||
EnsureTlsSetup();
|
||||
auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
|
||||
client_max->EnableDecryption();
|
||||
auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
|
||||
server_max->EnableDecryption();
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 100);
|
||||
Connect();
|
||||
SendReceive(127);
|
||||
|
||||
CheckRecordSizes(client_, client_max, 100);
|
||||
CheckRecordSizes(server_, server_max, 64);
|
||||
}
|
||||
|
||||
// This just modifies the encrypted payload so to include a few extra zeros.
|
||||
class TlsRecordExpander : public TlsRecordFilter {
|
||||
public:
|
||||
TlsRecordExpander(const std::shared_ptr<TlsAgent>& a, size_t expansion)
|
||||
: TlsRecordFilter(a), expansion_(expansion) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& data,
|
||||
DataBuffer* changed) {
|
||||
if (header.content_type() != kTlsApplicationDataType) {
|
||||
return KEEP;
|
||||
}
|
||||
changed->Allocate(data.len() + expansion_);
|
||||
changed->Write(0, data.data(), data.len());
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t expansion_;
|
||||
};
|
||||
|
||||
// Tweak the plaintext of server records so that they exceed the client's limit.
|
||||
TEST_P(TlsConnectTls13, RecordSizePlaintextExceed) {
|
||||
EnsureTlsSetup();
|
||||
auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 1);
|
||||
server_expand->EnableDecryption();
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
|
||||
server_->SendData(100);
|
||||
|
||||
client_->ExpectReadWriteError();
|
||||
ExpectAlert(client_, kTlsAlertRecordOverflow);
|
||||
client_->ReadBytes(100);
|
||||
EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
|
||||
|
||||
// Consume the alert at the server.
|
||||
server_->Handshake();
|
||||
server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
|
||||
}
|
||||
|
||||
// Tweak the ciphertext of server records so that they greatly exceed the limit.
|
||||
// This requires a much larger expansion than for plaintext to trigger the
|
||||
// guard, which runs before decryption (current allowance is 304 octets).
|
||||
TEST_P(TlsConnectTls13, RecordSizeCiphertextExceed) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
|
||||
auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 320);
|
||||
server_->SendData(100);
|
||||
|
||||
client_->ExpectReadWriteError();
|
||||
ExpectAlert(client_, kTlsAlertRecordOverflow);
|
||||
client_->ReadBytes(100);
|
||||
EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
|
||||
|
||||
// Consume the alert at the server.
|
||||
server_->Handshake();
|
||||
server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
|
||||
}
|
||||
|
||||
// This indiscriminately adds padding to application data records.
|
||||
class TlsRecordPadder : public TlsRecordFilter {
|
||||
public:
|
||||
TlsRecordPadder(const std::shared_ptr<TlsAgent>& a, size_t padding)
|
||||
: TlsRecordFilter(a), padding_(padding) {}
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& record, size_t* offset,
|
||||
DataBuffer* output) override {
|
||||
if (header.content_type() != kTlsApplicationDataType) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
uint8_t inner_content_type;
|
||||
DataBuffer plaintext;
|
||||
if (!Unprotect(header, record, &inner_content_type, &plaintext)) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
if (inner_content_type != kTlsApplicationDataType) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
DataBuffer ciphertext;
|
||||
bool ok =
|
||||
Protect(header, inner_content_type, plaintext, &ciphertext, padding_);
|
||||
EXPECT_TRUE(ok);
|
||||
if (!ok) {
|
||||
return KEEP;
|
||||
}
|
||||
*offset = header.Write(output, *offset, ciphertext);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t padding_;
|
||||
};
|
||||
|
||||
TEST_P(TlsConnectTls13, RecordSizeExceedPad) {
|
||||
EnsureTlsSetup();
|
||||
auto server_max = std::make_shared<TlsRecordMaximum>(server_);
|
||||
auto server_expand = std::make_shared<TlsRecordPadder>(server_, 1);
|
||||
server_->SetFilter(std::make_shared<ChainedPacketFilter>(
|
||||
ChainedPacketFilterInit({server_max, server_expand})));
|
||||
server_expand->EnableDecryption();
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
|
||||
server_->SendData(100);
|
||||
|
||||
client_->ExpectReadWriteError();
|
||||
ExpectAlert(client_, kTlsAlertRecordOverflow);
|
||||
client_->ReadBytes(100);
|
||||
EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
|
||||
|
||||
// Consume the alert at the server.
|
||||
server_->Handshake();
|
||||
server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeBadValues) {
|
||||
EnsureTlsSetup();
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_OptionSet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, 63));
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_OptionSet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, -1));
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_OptionSet(server_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, 16386));
|
||||
Connect();
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeGetValues) {
|
||||
EnsureTlsSetup();
|
||||
int v;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_OptionGet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, &v));
|
||||
EXPECT_EQ(16385, v);
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 300);
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_OptionGet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, &v));
|
||||
EXPECT_EQ(300, v);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// The value of the extension is capped by the maximum version of the client.
|
||||
TEST_P(TlsConnectGeneric, RecordSizeCapExtensionClient) {
|
||||
EnsureTlsSetup();
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
|
||||
auto capture =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_record_size_limit_xtn);
|
||||
capture->EnableDecryption();
|
||||
Connect();
|
||||
|
||||
uint64_t val = 0;
|
||||
EXPECT_TRUE(capture->extension().Read(0, 2, &val));
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
EXPECT_EQ(16384U, val) << "Extension should be capped";
|
||||
} else {
|
||||
EXPECT_EQ(16385U, val);
|
||||
}
|
||||
}
|
||||
|
||||
// The value of the extension is capped by the maximum version of the server.
|
||||
TEST_P(TlsConnectGeneric, RecordSizeCapExtensionServer) {
|
||||
EnsureTlsSetup();
|
||||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
|
||||
auto capture =
|
||||
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_record_size_limit_xtn);
|
||||
capture->EnableDecryption();
|
||||
Connect();
|
||||
|
||||
uint64_t val = 0;
|
||||
EXPECT_TRUE(capture->extension().Read(0, 2, &val));
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
EXPECT_EQ(16384U, val) << "Extension should be capped";
|
||||
} else {
|
||||
EXPECT_EQ(16385U, val);
|
||||
}
|
||||
}
|
||||
|
||||
// Damage the client extension and the handshake fails, but the server
|
||||
// doesn't generate a validation error.
|
||||
TEST_P(TlsConnectGenericPre13, RecordSizeClientExtensionInvalid) {
|
||||
EnsureTlsSetup();
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
|
||||
static const uint8_t v[] = {0xf4, 0x1f};
|
||||
MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_record_size_limit_xtn,
|
||||
DataBuffer(v, sizeof(v)));
|
||||
ConnectExpectAlert(server_, kTlsAlertDecryptError);
|
||||
}
|
||||
|
||||
// Special handling for TLS 1.3, where the alert isn't read.
|
||||
TEST_F(TlsConnectStreamTls13, RecordSizeClientExtensionInvalid) {
|
||||
EnsureTlsSetup();
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
|
||||
static const uint8_t v[] = {0xf4, 0x1f};
|
||||
MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_record_size_limit_xtn,
|
||||
DataBuffer(v, sizeof(v)));
|
||||
client_->ExpectSendAlert(kTlsAlertBadRecordMac);
|
||||
server_->ExpectSendAlert(kTlsAlertBadRecordMac);
|
||||
ConnectExpectFail();
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeServerExtensionInvalid) {
|
||||
EnsureTlsSetup();
|
||||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
|
||||
static const uint8_t v[] = {0xf4, 0x1f};
|
||||
auto replace = MakeTlsFilter<TlsExtensionReplacer>(
|
||||
server_, ssl_record_size_limit_xtn, DataBuffer(v, sizeof(v)));
|
||||
replace->EnableDecryption();
|
||||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
}
|
||||
|
||||
class RecordSizeDefaultsTest : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &default_));
|
||||
}
|
||||
void TearDown() {
|
||||
// Make sure to restore the default value at the end.
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, default_));
|
||||
}
|
||||
|
||||
private:
|
||||
PRIntn default_ = 0;
|
||||
};
|
||||
|
||||
TEST_F(RecordSizeDefaultsTest, RecordSizeBadValues) {
|
||||
EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 63));
|
||||
EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, -1));
|
||||
EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 16386));
|
||||
}
|
||||
|
||||
TEST_F(RecordSizeDefaultsTest, RecordSizeGetValue) {
|
||||
int v;
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &v));
|
||||
EXPECT_EQ(16385, v);
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 3000));
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &v));
|
||||
EXPECT_EQ(3000, v);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
|
@ -939,9 +939,9 @@ static bool ErrorIsNonFatal(PRErrorCode code) {
|
|||
}
|
||||
|
||||
void TlsAgent::SendData(size_t bytes, size_t blocksize) {
|
||||
uint8_t block[4096];
|
||||
uint8_t block[16385]; // One larger than the maximum record size.
|
||||
|
||||
ASSERT_LT(blocksize, sizeof(block));
|
||||
ASSERT_LE(blocksize, sizeof(block));
|
||||
|
||||
while (bytes) {
|
||||
size_t tosend = std::min(blocksize, bytes);
|
||||
|
|
|
@ -410,7 +410,7 @@ bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
|
|||
bool TlsRecordFilter::Protect(const TlsRecordHeader& header,
|
||||
uint8_t inner_content_type,
|
||||
const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext) {
|
||||
DataBuffer* ciphertext, size_t padding) {
|
||||
if (!cipher_spec_ || header.content_type() != kTlsApplicationDataType) {
|
||||
*ciphertext = plaintext;
|
||||
return true;
|
||||
|
@ -418,8 +418,10 @@ bool TlsRecordFilter::Protect(const TlsRecordHeader& header,
|
|||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << "protect: " << header.sequence_number() << std::endl;
|
||||
}
|
||||
DataBuffer padded = plaintext;
|
||||
padded.Write(padded.len(), inner_content_type, 1);
|
||||
DataBuffer padded;
|
||||
padded.Allocate(plaintext.len() + 1 + padding);
|
||||
size_t offset = padded.Write(0, plaintext.data(), plaintext.len());
|
||||
padded.Write(offset, inner_content_type, 1);
|
||||
return cipher_spec_->Protect(header, padded, ciphertext);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,8 @@ class TlsRecordFilter : public PacketFilter {
|
|||
bool Unprotect(const TlsRecordHeader& header, const DataBuffer& cipherText,
|
||||
uint8_t* inner_content_type, DataBuffer* plaintext);
|
||||
bool Protect(const TlsRecordHeader& header, uint8_t inner_content_type,
|
||||
const DataBuffer& plaintext, DataBuffer* ciphertext);
|
||||
const DataBuffer& plaintext, DataBuffer* ciphertext,
|
||||
size_t padding = 0);
|
||||
|
||||
protected:
|
||||
// There are two filter functions which can be overriden. Both are
|
||||
|
@ -506,6 +507,22 @@ class TlsClientHelloVersionChanger : public TlsHandshakeFilter {
|
|||
std::weak_ptr<TlsAgent> server_;
|
||||
};
|
||||
|
||||
// Damage a record.
|
||||
class TlsRecordLastByteDamager : public TlsRecordFilter {
|
||||
public:
|
||||
TlsRecordLastByteDamager(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsRecordFilter(a) {}
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& data,
|
||||
DataBuffer* changed) override {
|
||||
*changed = data;
|
||||
changed->data()[changed->len() - 1]++;
|
||||
return CHANGE;
|
||||
}
|
||||
};
|
||||
|
||||
// This class selectively drops complete writes. This relies on the fact that
|
||||
// writes in libssl are on record boundaries.
|
||||
class SelectiveDropFilter : public PacketFilter {
|
||||
|
|
|
@ -33,7 +33,3 @@ ifdef NSS_BUILD_CAPI
|
|||
DIRS += capi
|
||||
endif
|
||||
endif
|
||||
|
||||
#ifeq ($(OS_ARCH), Darwin)
|
||||
#DIRS += nssmkey
|
||||
#endif
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include manifest.mn
|
||||
include $(CORE_DEPTH)/coreconf/config.mk
|
||||
include config.mk
|
||||
|
||||
EXTRA_LIBS = \
|
||||
$(DIST)/lib/$(LIB_PREFIX)nssckfw.$(LIB_SUFFIX) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
# can't do this in manifest.mn because OS_TARGET isn't defined there.
|
||||
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
|
||||
|
||||
ifdef NS_USE_GCC
|
||||
EXTRA_LIBS += \
|
||||
-L$(NSPR_LIB_DIR) \
|
||||
-lplc4 \
|
||||
-lplds4 \
|
||||
-lnspr4 \
|
||||
$(NULL)
|
||||
else
|
||||
EXTRA_SHARED_LIBS += \
|
||||
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \
|
||||
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \
|
||||
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \
|
||||
$(NULL)
|
||||
endif # NS_USE_GCC
|
||||
else
|
||||
|
||||
EXTRA_LIBS += \
|
||||
-L$(NSPR_LIB_DIR) \
|
||||
-lplc4 \
|
||||
-lplds4 \
|
||||
-lnspr4 \
|
||||
-framework Security \
|
||||
-framework CoreServices \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
# Generate certdata.c.
|
||||
generate:
|
||||
perl certdata.perl < certdata.txt
|
||||
|
||||
# This'll need some help from a build person.
|
||||
|
||||
|
||||
ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.1)
|
||||
DSO_LDOPTS = -bM:SRE -bh:4 -bnoentry
|
||||
EXTRA_DSO_LDOPTS = -lc
|
||||
MKSHLIB = xlC $(DSO_LDOPTS)
|
||||
|
||||
$(SHARED_LIBRARY): $(OBJS)
|
||||
@$(MAKE_OBJDIR)
|
||||
rm -f $@
|
||||
$(MKSHLIB) -o $@ $(OBJS) $(EXTRA_LIBS) $(EXTRA_DSO_LDOPTS)
|
||||
chmod +x $@
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.2)
|
||||
LD += -G
|
||||
endif
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
This Cryptoki module provides acces to certs and keys stored in
|
||||
Macintosh key Ring.
|
||||
|
||||
- It does not yet export PKCS #12 keys. To get this to work should be
|
||||
implemented using exporting the key object in PKCS #8 wrapped format.
|
||||
PSM work needs to happen before this can be completed.
|
||||
- It does not import or export CA Root trust from the mac keychain.
|
||||
- It does not handle S/MIME objects (pkcs #7 in mac keychain terms?).
|
||||
- The AuthRoots don't show up on the default list.
|
||||
- Only RSA keys are supported currently.
|
||||
|
||||
There are a number of things that have not been tested that other PKCS #11
|
||||
apps may need:
|
||||
- reading Modulus and Public Exponents from private keys and public keys.
|
||||
- storing public keys.
|
||||
- setting attributes other than CKA_ID and CKA_LABEL.
|
||||
|
||||
Other TODOs:
|
||||
- Check for and plug memory leaks.
|
||||
- Need to map mac errors into something more intellegible than
|
||||
CKR_GENERAL_ERROR.
|
|
@ -1,182 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CKMK_H
|
||||
#define CKMK_H 1
|
||||
|
||||
#include <Security/SecKeychainSearch.h>
|
||||
#include <Security/SecKeychainItem.h>
|
||||
#include <Security/SecKeychain.h>
|
||||
#include <Security/cssmtype.h>
|
||||
#include <Security/cssmapi.h>
|
||||
#include <Security/SecKey.h>
|
||||
#include <Security/SecCertificate.h>
|
||||
|
||||
#define NTO
|
||||
|
||||
#include "nssckmdt.h"
|
||||
#include "nssckfw.h"
|
||||
/*
|
||||
* I'm including this for access to the arena functions.
|
||||
* Looks like we should publish that API.
|
||||
*/
|
||||
#ifndef BASE_H
|
||||
#include "base.h"
|
||||
#endif /* BASE_H */
|
||||
/*
|
||||
* This is where the Netscape extensions live, at least for now.
|
||||
*/
|
||||
#ifndef CKT_H
|
||||
#include "ckt.h"
|
||||
#endif /* CKT_H */
|
||||
|
||||
/*
|
||||
* statically defined raw objects. Allows us to data description objects
|
||||
* to this PKCS #11 module.
|
||||
*/
|
||||
struct ckmkRawObjectStr {
|
||||
CK_ULONG n;
|
||||
const CK_ATTRIBUTE_TYPE *types;
|
||||
const NSSItem *items;
|
||||
};
|
||||
typedef struct ckmkRawObjectStr ckmkRawObject;
|
||||
|
||||
/*
|
||||
* Key/Cert Items
|
||||
*/
|
||||
struct ckmkItemObjectStr {
|
||||
SecKeychainItemRef itemRef;
|
||||
SecItemClass itemClass;
|
||||
PRBool hasID;
|
||||
NSSItem modify;
|
||||
NSSItem private;
|
||||
NSSItem encrypt;
|
||||
NSSItem decrypt;
|
||||
NSSItem derive;
|
||||
NSSItem sign;
|
||||
NSSItem signRecover;
|
||||
NSSItem verify;
|
||||
NSSItem verifyRecover;
|
||||
NSSItem wrap;
|
||||
NSSItem unwrap;
|
||||
NSSItem label;
|
||||
NSSItem subject;
|
||||
NSSItem issuer;
|
||||
NSSItem serial;
|
||||
NSSItem derCert;
|
||||
NSSItem id;
|
||||
NSSItem modulus;
|
||||
NSSItem exponent;
|
||||
NSSItem privateExponent;
|
||||
NSSItem prime1;
|
||||
NSSItem prime2;
|
||||
NSSItem exponent1;
|
||||
NSSItem exponent2;
|
||||
NSSItem coefficient;
|
||||
};
|
||||
typedef struct ckmkItemObjectStr ckmkItemObject;
|
||||
|
||||
typedef enum {
|
||||
ckmkRaw,
|
||||
ckmkItem,
|
||||
} ckmkObjectType;
|
||||
|
||||
/*
|
||||
* all the various types of objects are abstracted away in cobject and
|
||||
* cfind as ckmkInternalObjects.
|
||||
*/
|
||||
struct ckmkInternalObjectStr {
|
||||
ckmkObjectType type;
|
||||
union {
|
||||
ckmkRawObject raw;
|
||||
ckmkItemObject item;
|
||||
} u;
|
||||
CK_OBJECT_CLASS objClass;
|
||||
NSSItem hashKey;
|
||||
unsigned char hashKeyData[128];
|
||||
NSSCKMDObject mdObject;
|
||||
};
|
||||
typedef struct ckmkInternalObjectStr ckmkInternalObject;
|
||||
|
||||
/* our raw object data array */
|
||||
NSS_EXTERN_DATA ckmkInternalObject nss_ckmk_data[];
|
||||
NSS_EXTERN_DATA const PRUint32 nss_ckmk_nObjects;
|
||||
|
||||
NSS_EXTERN_DATA const CK_VERSION nss_ckmk_CryptokiVersion;
|
||||
NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_ManufacturerID;
|
||||
NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_LibraryDescription;
|
||||
NSS_EXTERN_DATA const CK_VERSION nss_ckmk_LibraryVersion;
|
||||
NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_SlotDescription;
|
||||
NSS_EXTERN_DATA const CK_VERSION nss_ckmk_HardwareVersion;
|
||||
NSS_EXTERN_DATA const CK_VERSION nss_ckmk_FirmwareVersion;
|
||||
NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenLabel;
|
||||
NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenModel;
|
||||
NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenSerialNumber;
|
||||
|
||||
NSS_EXTERN_DATA const NSSCKMDInstance nss_ckmk_mdInstance;
|
||||
NSS_EXTERN_DATA const NSSCKMDSlot nss_ckmk_mdSlot;
|
||||
NSS_EXTERN_DATA const NSSCKMDToken nss_ckmk_mdToken;
|
||||
NSS_EXTERN_DATA const NSSCKMDMechanism nss_ckmk_mdMechanismRSA;
|
||||
|
||||
NSS_EXTERN NSSCKMDSession *
|
||||
nss_ckmk_CreateSession(
|
||||
NSSCKFWSession *fwSession,
|
||||
CK_RV *pError);
|
||||
|
||||
NSS_EXTERN NSSCKMDFindObjects *
|
||||
nss_ckmk_FindObjectsInit(
|
||||
NSSCKFWSession *fwSession,
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
CK_RV *pError);
|
||||
|
||||
/*
|
||||
* Object Utilities
|
||||
*/
|
||||
NSS_EXTERN NSSCKMDObject *
|
||||
nss_ckmk_CreateMDObject(
|
||||
NSSArena *arena,
|
||||
ckmkInternalObject *io,
|
||||
CK_RV *pError);
|
||||
|
||||
NSS_EXTERN NSSCKMDObject *
|
||||
nss_ckmk_CreateObject(
|
||||
NSSCKFWSession *fwSession,
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
CK_RV *pError);
|
||||
|
||||
NSS_EXTERN const NSSItem *
|
||||
nss_ckmk_FetchAttribute(
|
||||
ckmkInternalObject *io,
|
||||
CK_ATTRIBUTE_TYPE type,
|
||||
CK_RV *pError);
|
||||
|
||||
NSS_EXTERN void
|
||||
nss_ckmk_DestroyInternalObject(
|
||||
ckmkInternalObject *io);
|
||||
|
||||
unsigned char *
|
||||
nss_ckmk_DERUnwrap(
|
||||
unsigned char *src,
|
||||
int size,
|
||||
int *outSize,
|
||||
unsigned char **next);
|
||||
|
||||
CK_ULONG
|
||||
nss_ckmk_GetULongAttribute(
|
||||
CK_ATTRIBUTE_TYPE type,
|
||||
CK_ATTRIBUTE *template,
|
||||
CK_ULONG templateSize,
|
||||
CK_RV *pError);
|
||||
|
||||
#define NSS_CKMK_ARRAY_SIZE(x) ((sizeof(x)) / (sizeof((x)[0])))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define CKMK_MACERR(str, err) cssmPerror(str, err)
|
||||
#else
|
||||
#define CKMK_MACERR(str, err)
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,17 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* Library identity and versioning */
|
||||
|
||||
#include "nssmkey.h"
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define _DEBUG_STRING " (debug)"
|
||||
#else
|
||||
#define _DEBUG_STRING ""
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Version information
|
||||
*/
|
||||
const char __nss_ckmk_version[] = "Version: NSS Access to the MAC OS X Key Ring " NSS_CKMK_LIBRARY_VERSION _DEBUG_STRING;
|
|
@ -1,24 +0,0 @@
|
|||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
ifdef BUILD_IDG
|
||||
DEFINES += -DNSSDEBUG
|
||||
endif
|
||||
|
||||
ifdef NS_USE_CKFW_TRACE
|
||||
DEFINES += -DTRACE
|
||||
endif
|
||||
|
||||
#
|
||||
# Override TARGETS variable so that only static libraries
|
||||
# are specifed as dependencies within rules.mk.
|
||||
#
|
||||
|
||||
TARGETS = $(LIBRARY)
|
||||
SHARED_LIBRARY =
|
||||
IMPORT_LIBRARY =
|
||||
PROGRAM =
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* nssmkey/manchor.c
|
||||
*
|
||||
* This file "anchors" the actual cryptoki entry points in this module's
|
||||
* shared library, which is required for dynamic loading. See the
|
||||
* comments in nssck.api for more information.
|
||||
*/
|
||||
|
||||
#include "ckmk.h"
|
||||
|
||||
#define MODULE_NAME ckmk
|
||||
#define INSTANCE_NAME (NSSCKMDInstance *)&nss_ckmk_mdInstance
|
||||
#include "nssck.api"
|
|
@ -1,33 +0,0 @@
|
|||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
CORE_DEPTH = ../../../..
|
||||
|
||||
MODULE = nss
|
||||
MAPFILE = $(OBJDIR)/nssmkey.def
|
||||
|
||||
EXPORTS = \
|
||||
nssmkey.h \
|
||||
$(NULL)
|
||||
|
||||
CSRCS = \
|
||||
manchor.c \
|
||||
mconstants.c \
|
||||
mfind.c \
|
||||
minst.c \
|
||||
mobject.c \
|
||||
mrsa.c \
|
||||
msession.c \
|
||||
mslot.c \
|
||||
mtoken.c \
|
||||
ckmkver.c \
|
||||
staticobj.c \
|
||||
$(NULL)
|
||||
|
||||
REQUIRES = nspr
|
||||
|
||||
LIBRARY_NAME = nssmkey
|
||||
|
||||
#EXTRA_SHARED_LIBS = -L$(DIST)/lib -lnssckfw -lnssb -lplc4 -lplds4
|
|
@ -1,61 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* nssmkey/constants.c
|
||||
*
|
||||
* Identification and other constants, all collected here in one place.
|
||||
*/
|
||||
|
||||
#ifndef NSSBASET_H
|
||||
#include "nssbaset.h"
|
||||
#endif /* NSSBASET_H */
|
||||
|
||||
#ifndef NSSCKT_H
|
||||
#include "nssckt.h"
|
||||
#endif /* NSSCKT_H */
|
||||
|
||||
#include "nssmkey.h"
|
||||
|
||||
NSS_IMPLEMENT_DATA const CK_VERSION
|
||||
nss_ckmk_CryptokiVersion = {
|
||||
NSS_CKMK_CRYPTOKI_VERSION_MAJOR,
|
||||
NSS_CKMK_CRYPTOKI_VERSION_MINOR
|
||||
};
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSUTF8 *
|
||||
nss_ckmk_ManufacturerID = (NSSUTF8 *)"Mozilla Foundation";
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSUTF8 *
|
||||
nss_ckmk_LibraryDescription = (NSSUTF8 *)"NSS Access to Mac OS X Key Ring";
|
||||
|
||||
NSS_IMPLEMENT_DATA const CK_VERSION
|
||||
nss_ckmk_LibraryVersion = {
|
||||
NSS_CKMK_LIBRARY_VERSION_MAJOR,
|
||||
NSS_CKMK_LIBRARY_VERSION_MINOR
|
||||
};
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSUTF8 *
|
||||
nss_ckmk_SlotDescription = (NSSUTF8 *)"Mac OS X Key Ring";
|
||||
|
||||
NSS_IMPLEMENT_DATA const CK_VERSION
|
||||
nss_ckmk_HardwareVersion = {
|
||||
NSS_CKMK_HARDWARE_VERSION_MAJOR,
|
||||
NSS_CKMK_HARDWARE_VERSION_MINOR
|
||||
};
|
||||
|
||||
NSS_IMPLEMENT_DATA const CK_VERSION
|
||||
nss_ckmk_FirmwareVersion = {
|
||||
NSS_CKMK_FIRMWARE_VERSION_MAJOR,
|
||||
NSS_CKMK_FIRMWARE_VERSION_MINOR
|
||||
};
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSUTF8 *
|
||||
nss_ckmk_TokenLabel = (NSSUTF8 *)"Mac OS X Key Ring";
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSUTF8 *
|
||||
nss_ckmk_TokenModel = (NSSUTF8 *)"1";
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSUTF8 *
|
||||
nss_ckmk_TokenSerialNumber = (NSSUTF8 *)"1";
|
|
@ -1,352 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CKMK_H
|
||||
#include "ckmk.h"
|
||||
#endif /* CKMK_H */
|
||||
|
||||
/*
|
||||
* nssmkey/mfind.c
|
||||
*
|
||||
* This file implements the NSSCKMDFindObjects object for the
|
||||
* "nssmkey" cryptoki module.
|
||||
*/
|
||||
|
||||
struct ckmkFOStr {
|
||||
NSSArena *arena;
|
||||
CK_ULONG n;
|
||||
CK_ULONG i;
|
||||
ckmkInternalObject **objs;
|
||||
};
|
||||
|
||||
static void
|
||||
ckmk_mdFindObjects_Final(
|
||||
NSSCKMDFindObjects *mdFindObjects,
|
||||
NSSCKFWFindObjects *fwFindObjects,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc;
|
||||
NSSArena *arena = fo->arena;
|
||||
PRUint32 i;
|
||||
|
||||
/* walk down an free the unused 'objs' */
|
||||
for (i = fo->i; i < fo->n; i++) {
|
||||
nss_ckmk_DestroyInternalObject(fo->objs[i]);
|
||||
}
|
||||
|
||||
nss_ZFreeIf(fo->objs);
|
||||
nss_ZFreeIf(fo);
|
||||
nss_ZFreeIf(mdFindObjects);
|
||||
if ((NSSArena *)NULL != arena) {
|
||||
NSSArena_Destroy(arena);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static NSSCKMDObject *
|
||||
ckmk_mdFindObjects_Next(
|
||||
NSSCKMDFindObjects *mdFindObjects,
|
||||
NSSCKFWFindObjects *fwFindObjects,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
NSSArena *arena,
|
||||
CK_RV *pError)
|
||||
{
|
||||
struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc;
|
||||
ckmkInternalObject *io;
|
||||
|
||||
if (fo->i == fo->n) {
|
||||
*pError = CKR_OK;
|
||||
return (NSSCKMDObject *)NULL;
|
||||
}
|
||||
|
||||
io = fo->objs[fo->i];
|
||||
fo->i++;
|
||||
|
||||
return nss_ckmk_CreateMDObject(arena, io, pError);
|
||||
}
|
||||
|
||||
static CK_BBOOL
|
||||
ckmk_attrmatch(
|
||||
CK_ATTRIBUTE_PTR a,
|
||||
ckmkInternalObject *o)
|
||||
{
|
||||
PRBool prb;
|
||||
const NSSItem *b;
|
||||
CK_RV error;
|
||||
|
||||
b = nss_ckmk_FetchAttribute(o, a->type, &error);
|
||||
if (b == NULL) {
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
if (a->ulValueLen != b->size) {
|
||||
/* match a decoded serial number */
|
||||
if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) {
|
||||
int len;
|
||||
unsigned char *data;
|
||||
|
||||
data = nss_ckmk_DERUnwrap(b->data, b->size, &len, NULL);
|
||||
if ((len == a->ulValueLen) &&
|
||||
nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) {
|
||||
return CK_TRUE;
|
||||
}
|
||||
}
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL);
|
||||
|
||||
if (PR_TRUE == prb) {
|
||||
return CK_TRUE;
|
||||
} else {
|
||||
return CK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static CK_BBOOL
|
||||
ckmk_match(
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
ckmkInternalObject *o)
|
||||
{
|
||||
CK_ULONG i;
|
||||
|
||||
for (i = 0; i < ulAttributeCount; i++) {
|
||||
if (CK_FALSE == ckmk_attrmatch(&pTemplate[i], o)) {
|
||||
return CK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Every attribute passed */
|
||||
return CK_TRUE;
|
||||
}
|
||||
|
||||
#define CKMK_ITEM_CHUNK 20
|
||||
|
||||
#define PUT_OBJECT(obj, err, size, count, list) \
|
||||
{ \
|
||||
if (count >= size) { \
|
||||
(list) = (list) ? nss_ZREALLOCARRAY(list, ckmkInternalObject *, \
|
||||
((size) + \
|
||||
CKMK_ITEM_CHUNK)) \
|
||||
: nss_ZNEWARRAY(NULL, ckmkInternalObject *, \
|
||||
((size) + \
|
||||
CKMK_ITEM_CHUNK)); \
|
||||
if ((ckmkInternalObject **)NULL == list) { \
|
||||
err = CKR_HOST_MEMORY; \
|
||||
goto loser; \
|
||||
} \
|
||||
(size) += CKMK_ITEM_CHUNK; \
|
||||
} \
|
||||
(list)[count] = (obj); \
|
||||
count++; \
|
||||
}
|
||||
|
||||
/* find all the certs that represent the appropriate object (cert, priv key, or
|
||||
* pub key) in the cert store.
|
||||
*/
|
||||
static PRUint32
|
||||
collect_class(
|
||||
CK_OBJECT_CLASS objClass,
|
||||
SecItemClass itemClass,
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
ckmkInternalObject ***listp,
|
||||
PRUint32 *sizep,
|
||||
PRUint32 count,
|
||||
CK_RV *pError)
|
||||
{
|
||||
ckmkInternalObject *next = NULL;
|
||||
SecKeychainSearchRef searchRef = 0;
|
||||
SecKeychainItemRef itemRef = 0;
|
||||
OSStatus error;
|
||||
|
||||
/* future, build the attribute list based on the template
|
||||
* so we can refine the search */
|
||||
error = SecKeychainSearchCreateFromAttributes(
|
||||
NULL, itemClass, NULL, &searchRef);
|
||||
|
||||
while (noErr == SecKeychainSearchCopyNext(searchRef, &itemRef)) {
|
||||
/* if we don't have an internal object structure, get one */
|
||||
if ((ckmkInternalObject *)NULL == next) {
|
||||
next = nss_ZNEW(NULL, ckmkInternalObject);
|
||||
if ((ckmkInternalObject *)NULL == next) {
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
goto loser;
|
||||
}
|
||||
}
|
||||
/* fill in the relevant object data */
|
||||
next->type = ckmkItem;
|
||||
next->objClass = objClass;
|
||||
next->u.item.itemRef = itemRef;
|
||||
next->u.item.itemClass = itemClass;
|
||||
|
||||
/* see if this is one of the objects we are looking for */
|
||||
if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, next)) {
|
||||
/* yes, put it on the list */
|
||||
PUT_OBJECT(next, *pError, *sizep, count, *listp);
|
||||
next = NULL; /* this one is on the list, need to allocate a new one now */
|
||||
} else {
|
||||
/* no , release the current item and clear out the structure for reuse */
|
||||
CFRelease(itemRef);
|
||||
/* don't cache the values we just loaded */
|
||||
nsslibc_memset(next, 0, sizeof(*next));
|
||||
}
|
||||
}
|
||||
loser:
|
||||
if (searchRef) {
|
||||
CFRelease(searchRef);
|
||||
}
|
||||
nss_ZFreeIf(next);
|
||||
return count;
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
collect_objects(
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
ckmkInternalObject ***listp,
|
||||
CK_RV *pError)
|
||||
{
|
||||
PRUint32 i;
|
||||
PRUint32 count = 0;
|
||||
PRUint32 size = 0;
|
||||
CK_OBJECT_CLASS objClass;
|
||||
|
||||
/*
|
||||
* first handle the static build in objects (if any)
|
||||
*/
|
||||
for (i = 0; i < nss_ckmk_nObjects; i++) {
|
||||
ckmkInternalObject *o = (ckmkInternalObject *)&nss_ckmk_data[i];
|
||||
|
||||
if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, o)) {
|
||||
PUT_OBJECT(o, *pError, size, count, *listp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* now handle the various object types
|
||||
*/
|
||||
objClass = nss_ckmk_GetULongAttribute(CKA_CLASS,
|
||||
pTemplate, ulAttributeCount, pError);
|
||||
if (CKR_OK != *pError) {
|
||||
objClass = CK_INVALID_HANDLE;
|
||||
}
|
||||
*pError = CKR_OK;
|
||||
switch (objClass) {
|
||||
case CKO_CERTIFICATE:
|
||||
count = collect_class(objClass, kSecCertificateItemClass,
|
||||
pTemplate, ulAttributeCount, listp,
|
||||
&size, count, pError);
|
||||
break;
|
||||
case CKO_PUBLIC_KEY:
|
||||
count = collect_class(objClass, CSSM_DL_DB_RECORD_PUBLIC_KEY,
|
||||
pTemplate, ulAttributeCount, listp,
|
||||
&size, count, pError);
|
||||
break;
|
||||
case CKO_PRIVATE_KEY:
|
||||
count = collect_class(objClass, CSSM_DL_DB_RECORD_PRIVATE_KEY,
|
||||
pTemplate, ulAttributeCount, listp,
|
||||
&size, count, pError);
|
||||
break;
|
||||
/* all of them */
|
||||
case CK_INVALID_HANDLE:
|
||||
count = collect_class(CKO_CERTIFICATE, kSecCertificateItemClass,
|
||||
pTemplate, ulAttributeCount, listp,
|
||||
&size, count, pError);
|
||||
count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PUBLIC_KEY,
|
||||
pTemplate, ulAttributeCount, listp,
|
||||
&size, count, pError);
|
||||
count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PRIVATE_KEY,
|
||||
pTemplate, ulAttributeCount, listp,
|
||||
&size, count, pError);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (CKR_OK != *pError) {
|
||||
goto loser;
|
||||
}
|
||||
|
||||
return count;
|
||||
loser:
|
||||
nss_ZFreeIf(*listp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NSS_IMPLEMENT NSSCKMDFindObjects *
|
||||
nss_ckmk_FindObjectsInit(
|
||||
NSSCKFWSession *fwSession,
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
CK_RV *pError)
|
||||
{
|
||||
/* This could be made more efficient. I'm rather rushed. */
|
||||
NSSArena *arena;
|
||||
NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL;
|
||||
struct ckmkFOStr *fo = (struct ckmkFOStr *)NULL;
|
||||
ckmkInternalObject **temp = (ckmkInternalObject **)NULL;
|
||||
|
||||
arena = NSSArena_Create();
|
||||
if ((NSSArena *)NULL == arena) {
|
||||
goto loser;
|
||||
}
|
||||
|
||||
rv = nss_ZNEW(arena, NSSCKMDFindObjects);
|
||||
if ((NSSCKMDFindObjects *)NULL == rv) {
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
goto loser;
|
||||
}
|
||||
|
||||
fo = nss_ZNEW(arena, struct ckmkFOStr);
|
||||
if ((struct ckmkFOStr *)NULL == fo) {
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
goto loser;
|
||||
}
|
||||
|
||||
fo->arena = arena;
|
||||
/* fo->n and fo->i are already zero */
|
||||
|
||||
rv->etc = (void *)fo;
|
||||
rv->Final = ckmk_mdFindObjects_Final;
|
||||
rv->Next = ckmk_mdFindObjects_Next;
|
||||
rv->null = (void *)NULL;
|
||||
|
||||
fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError);
|
||||
if (*pError != CKR_OK) {
|
||||
goto loser;
|
||||
}
|
||||
|
||||
fo->objs = nss_ZNEWARRAY(arena, ckmkInternalObject *, fo->n);
|
||||
if ((ckmkInternalObject **)NULL == fo->objs) {
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
goto loser;
|
||||
}
|
||||
|
||||
(void)nsslibc_memcpy(fo->objs, temp, sizeof(ckmkInternalObject *) * fo->n);
|
||||
nss_ZFreeIf(temp);
|
||||
temp = (ckmkInternalObject **)NULL;
|
||||
|
||||
return rv;
|
||||
|
||||
loser:
|
||||
nss_ZFreeIf(temp);
|
||||
nss_ZFreeIf(fo);
|
||||
nss_ZFreeIf(rv);
|
||||
if ((NSSArena *)NULL != arena) {
|
||||
NSSArena_Destroy(arena);
|
||||
}
|
||||
return (NSSCKMDFindObjects *)NULL;
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ckmk.h"
|
||||
|
||||
/*
|
||||
* nssmkey/minstance.c
|
||||
*
|
||||
* This file implements the NSSCKMDInstance object for the
|
||||
* "nssmkey" cryptoki module.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NSSCKMDInstance methods
|
||||
*/
|
||||
|
||||
static CK_ULONG
|
||||
ckmk_mdInstance_GetNSlots(
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (CK_ULONG)1;
|
||||
}
|
||||
|
||||
static CK_VERSION
|
||||
ckmk_mdInstance_GetCryptokiVersion(
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return nss_ckmk_CryptokiVersion;
|
||||
}
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdInstance_GetManufacturerID(
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_ManufacturerID;
|
||||
}
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdInstance_GetLibraryDescription(
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_LibraryDescription;
|
||||
}
|
||||
|
||||
static CK_VERSION
|
||||
ckmk_mdInstance_GetLibraryVersion(
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return nss_ckmk_LibraryVersion;
|
||||
}
|
||||
|
||||
static CK_RV
|
||||
ckmk_mdInstance_GetSlots(
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
NSSCKMDSlot *slots[])
|
||||
{
|
||||
slots[0] = (NSSCKMDSlot *)&nss_ckmk_mdSlot;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_BBOOL
|
||||
ckmk_mdInstance_ModuleHandlesSessionObjects(
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
/* we don't want to allow any session object creation, at least
|
||||
* until we can investigate whether or not we can use those objects
|
||||
*/
|
||||
return CK_TRUE;
|
||||
}
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSCKMDInstance
|
||||
nss_ckmk_mdInstance = {
|
||||
(void *)NULL, /* etc */
|
||||
NULL, /* Initialize */
|
||||
NULL, /* Finalize */
|
||||
ckmk_mdInstance_GetNSlots,
|
||||
ckmk_mdInstance_GetCryptokiVersion,
|
||||
ckmk_mdInstance_GetManufacturerID,
|
||||
ckmk_mdInstance_GetLibraryDescription,
|
||||
ckmk_mdInstance_GetLibraryVersion,
|
||||
ckmk_mdInstance_ModuleHandlesSessionObjects,
|
||||
/*NULL, /* HandleSessionObjects */
|
||||
ckmk_mdInstance_GetSlots,
|
||||
NULL, /* WaitForSlotEvent */
|
||||
(void *)NULL /* null terminator */
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,479 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ckmk.h"
|
||||
|
||||
/* Sigh, For all the talk about 'ease of use', apple has hidden the interfaces
|
||||
* needed to be able to truly use CSSM. These came from their modification
|
||||
* to NSS's S/MIME code. The following two functions currently are not
|
||||
* part of the SecKey.h interface.
|
||||
*/
|
||||
OSStatus
|
||||
SecKeyGetCredentials(
|
||||
SecKeyRef keyRef,
|
||||
CSSM_ACL_AUTHORIZATION_TAG authTag,
|
||||
int type,
|
||||
const CSSM_ACCESS_CREDENTIALS **creds);
|
||||
|
||||
/* this function could be implemented using 'SecKeychainItemCopyKeychain' and
|
||||
* 'SecKeychainGetCSPHandle' */
|
||||
OSStatus
|
||||
SecKeyGetCSPHandle(
|
||||
SecKeyRef keyRef,
|
||||
CSSM_CSP_HANDLE *cspHandle);
|
||||
|
||||
typedef struct ckmkInternalCryptoOperationRSAPrivStr
|
||||
ckmkInternalCryptoOperationRSAPriv;
|
||||
struct ckmkInternalCryptoOperationRSAPrivStr {
|
||||
NSSCKMDCryptoOperation mdOperation;
|
||||
NSSCKMDMechanism *mdMechanism;
|
||||
ckmkInternalObject *iKey;
|
||||
NSSItem *buffer;
|
||||
CSSM_CC_HANDLE cssmContext;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CKMK_DECRYPT,
|
||||
CKMK_SIGN
|
||||
} ckmkRSAOpType;
|
||||
|
||||
/*
|
||||
* ckmk_mdCryptoOperationRSAPriv_Create
|
||||
*/
|
||||
static NSSCKMDCryptoOperation *
|
||||
ckmk_mdCryptoOperationRSAPriv_Create(
|
||||
const NSSCKMDCryptoOperation *proto,
|
||||
NSSCKMDMechanism *mdMechanism,
|
||||
NSSCKMDObject *mdKey,
|
||||
ckmkRSAOpType type,
|
||||
CK_RV *pError)
|
||||
{
|
||||
ckmkInternalObject *iKey = (ckmkInternalObject *)mdKey->etc;
|
||||
const NSSItem *classItem = nss_ckmk_FetchAttribute(iKey, CKA_CLASS, pError);
|
||||
const NSSItem *keyType = nss_ckmk_FetchAttribute(iKey, CKA_KEY_TYPE, pError);
|
||||
ckmkInternalCryptoOperationRSAPriv *iOperation;
|
||||
SecKeyRef privateKey;
|
||||
OSStatus macErr;
|
||||
CSSM_RETURN cssmErr;
|
||||
const CSSM_KEY *cssmKey;
|
||||
CSSM_CSP_HANDLE cspHandle;
|
||||
const CSSM_ACCESS_CREDENTIALS *creds = NULL;
|
||||
CSSM_CC_HANDLE cssmContext;
|
||||
CSSM_ACL_AUTHORIZATION_TAG authType;
|
||||
|
||||
/* make sure we have the right objects */
|
||||
if (((const NSSItem *)NULL == classItem) ||
|
||||
(sizeof(CK_OBJECT_CLASS) != classItem->size) ||
|
||||
(CKO_PRIVATE_KEY != *(CK_OBJECT_CLASS *)classItem->data) ||
|
||||
((const NSSItem *)NULL == keyType) ||
|
||||
(sizeof(CK_KEY_TYPE) != keyType->size) ||
|
||||
(CKK_RSA != *(CK_KEY_TYPE *)keyType->data)) {
|
||||
*pError = CKR_KEY_TYPE_INCONSISTENT;
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
|
||||
privateKey = (SecKeyRef)iKey->u.item.itemRef;
|
||||
macErr = SecKeyGetCSSMKey(privateKey, &cssmKey);
|
||||
if (noErr != macErr) {
|
||||
CKMK_MACERR("Getting CSSM Key", macErr);
|
||||
*pError = CKR_KEY_HANDLE_INVALID;
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
macErr = SecKeyGetCSPHandle(privateKey, &cspHandle);
|
||||
if (noErr != macErr) {
|
||||
CKMK_MACERR("Getting CSP for Key", macErr);
|
||||
*pError = CKR_KEY_HANDLE_INVALID;
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
switch (type) {
|
||||
case CKMK_DECRYPT:
|
||||
authType = CSSM_ACL_AUTHORIZATION_DECRYPT;
|
||||
break;
|
||||
case CKMK_SIGN:
|
||||
authType = CSSM_ACL_AUTHORIZATION_SIGN;
|
||||
break;
|
||||
default:
|
||||
*pError = CKR_GENERAL_ERROR;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "RSAPriv_Create: bad type = %d\n", type);
|
||||
#endif
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
|
||||
macErr = SecKeyGetCredentials(privateKey, authType, 0, &creds);
|
||||
if (noErr != macErr) {
|
||||
CKMK_MACERR("Getting Credentials for Key", macErr);
|
||||
*pError = CKR_KEY_HANDLE_INVALID;
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case CKMK_DECRYPT:
|
||||
cssmErr = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA,
|
||||
creds, cssmKey, CSSM_PADDING_PKCS1, &cssmContext);
|
||||
break;
|
||||
case CKMK_SIGN:
|
||||
cssmErr = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
|
||||
creds, cssmKey, &cssmContext);
|
||||
break;
|
||||
default:
|
||||
*pError = CKR_GENERAL_ERROR;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "RSAPriv_Create: bad type = %d\n", type);
|
||||
#endif
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
if (noErr != cssmErr) {
|
||||
CKMK_MACERR("Getting Context for Key", cssmErr);
|
||||
*pError = CKR_GENERAL_ERROR;
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
|
||||
iOperation = nss_ZNEW(NULL, ckmkInternalCryptoOperationRSAPriv);
|
||||
if ((ckmkInternalCryptoOperationRSAPriv *)NULL == iOperation) {
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
return (NSSCKMDCryptoOperation *)NULL;
|
||||
}
|
||||
iOperation->mdMechanism = mdMechanism;
|
||||
iOperation->iKey = iKey;
|
||||
iOperation->cssmContext = cssmContext;
|
||||
|
||||
nsslibc_memcpy(&iOperation->mdOperation,
|
||||
proto, sizeof(NSSCKMDCryptoOperation));
|
||||
iOperation->mdOperation.etc = iOperation;
|
||||
|
||||
return &iOperation->mdOperation;
|
||||
}
|
||||
|
||||
static void
|
||||
ckmk_mdCryptoOperationRSAPriv_Destroy(
|
||||
NSSCKMDCryptoOperation *mdOperation,
|
||||
NSSCKFWCryptoOperation *fwOperation,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
ckmkInternalCryptoOperationRSAPriv *iOperation =
|
||||
(ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
|
||||
|
||||
if (iOperation->buffer) {
|
||||
nssItem_Destroy(iOperation->buffer);
|
||||
}
|
||||
if (iOperation->cssmContext) {
|
||||
CSSM_DeleteContext(iOperation->cssmContext);
|
||||
}
|
||||
nss_ZFreeIf(iOperation);
|
||||
return;
|
||||
}
|
||||
|
||||
static CK_ULONG
|
||||
ckmk_mdCryptoOperationRSA_GetFinalLength(
|
||||
NSSCKMDCryptoOperation *mdOperation,
|
||||
NSSCKFWCryptoOperation *fwOperation,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
ckmkInternalCryptoOperationRSAPriv *iOperation =
|
||||
(ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
|
||||
const NSSItem *modulus =
|
||||
nss_ckmk_FetchAttribute(iOperation->iKey, CKA_MODULUS, pError);
|
||||
|
||||
return modulus->size;
|
||||
}
|
||||
|
||||
/*
|
||||
* ckmk_mdCryptoOperationRSADecrypt_GetOperationLength
|
||||
* we won't know the length until we actually decrypt the
|
||||
* input block. Since we go to all the work to decrypt the
|
||||
* the block, we'll save if for when the block is asked for
|
||||
*/
|
||||
static CK_ULONG
|
||||
ckmk_mdCryptoOperationRSADecrypt_GetOperationLength(
|
||||
NSSCKMDCryptoOperation *mdOperation,
|
||||
NSSCKFWCryptoOperation *fwOperation,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
const NSSItem *input,
|
||||
CK_RV *pError)
|
||||
{
|
||||
ckmkInternalCryptoOperationRSAPriv *iOperation =
|
||||
(ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
|
||||
CSSM_DATA cssmInput;
|
||||
CSSM_DATA cssmOutput = { 0, NULL };
|
||||
PRUint32 bytesDecrypted;
|
||||
CSSM_DATA remainder = { 0, NULL };
|
||||
NSSItem output;
|
||||
CSSM_RETURN cssmErr;
|
||||
|
||||
if (iOperation->buffer) {
|
||||
return iOperation->buffer->size;
|
||||
}
|
||||
|
||||
cssmInput.Data = input->data;
|
||||
cssmInput.Length = input->size;
|
||||
|
||||
cssmErr = CSSM_DecryptData(iOperation->cssmContext,
|
||||
&cssmInput, 1, &cssmOutput, 1,
|
||||
&bytesDecrypted, &remainder);
|
||||
if (CSSM_OK != cssmErr) {
|
||||
CKMK_MACERR("Decrypt Failed", cssmErr);
|
||||
*pError = CKR_DATA_INVALID;
|
||||
return 0;
|
||||
}
|
||||
/* we didn't suppy any buffers, so it should all be in remainder */
|
||||
output.data = nss_ZNEWARRAY(NULL, char, bytesDecrypted + remainder.Length);
|
||||
if (NULL == output.data) {
|
||||
free(cssmOutput.Data);
|
||||
free(remainder.Data);
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
return 0;
|
||||
}
|
||||
output.size = bytesDecrypted + remainder.Length;
|
||||
|
||||
if (0 != bytesDecrypted) {
|
||||
nsslibc_memcpy(output.data, cssmOutput.Data, bytesDecrypted);
|
||||
free(cssmOutput.Data);
|
||||
}
|
||||
if (0 != remainder.Length) {
|
||||
nsslibc_memcpy(((char *)output.data) + bytesDecrypted,
|
||||
remainder.Data, remainder.Length);
|
||||
free(remainder.Data);
|
||||
}
|
||||
|
||||
iOperation->buffer = nssItem_Duplicate(&output, NULL, NULL);
|
||||
nss_ZFreeIf(output.data);
|
||||
if ((NSSItem *)NULL == iOperation->buffer) {
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return iOperation->buffer->size;
|
||||
}
|
||||
|
||||
/*
|
||||
* ckmk_mdCryptoOperationRSADecrypt_UpdateFinal
|
||||
*
|
||||
* NOTE: ckmk_mdCryptoOperationRSADecrypt_GetOperationLength is presumed to
|
||||
* have been called previously.
|
||||
*/
|
||||
static CK_RV
|
||||
ckmk_mdCryptoOperationRSADecrypt_UpdateFinal(
|
||||
NSSCKMDCryptoOperation *mdOperation,
|
||||
NSSCKFWCryptoOperation *fwOperation,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
const NSSItem *input,
|
||||
NSSItem *output)
|
||||
{
|
||||
ckmkInternalCryptoOperationRSAPriv *iOperation =
|
||||
(ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
|
||||
NSSItem *buffer = iOperation->buffer;
|
||||
|
||||
if ((NSSItem *)NULL == buffer) {
|
||||
return CKR_GENERAL_ERROR;
|
||||
}
|
||||
nsslibc_memcpy(output->data, buffer->data, buffer->size);
|
||||
output->size = buffer->size;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ckmk_mdCryptoOperationRSASign_UpdateFinal
|
||||
*
|
||||
*/
|
||||
static CK_RV
|
||||
ckmk_mdCryptoOperationRSASign_UpdateFinal(
|
||||
NSSCKMDCryptoOperation *mdOperation,
|
||||
NSSCKFWCryptoOperation *fwOperation,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
const NSSItem *input,
|
||||
NSSItem *output)
|
||||
{
|
||||
ckmkInternalCryptoOperationRSAPriv *iOperation =
|
||||
(ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
|
||||
CSSM_DATA cssmInput;
|
||||
CSSM_DATA cssmOutput = { 0, NULL };
|
||||
CSSM_RETURN cssmErr;
|
||||
|
||||
cssmInput.Data = input->data;
|
||||
cssmInput.Length = input->size;
|
||||
|
||||
cssmErr = CSSM_SignData(iOperation->cssmContext, &cssmInput, 1,
|
||||
CSSM_ALGID_NONE, &cssmOutput);
|
||||
if (CSSM_OK != cssmErr) {
|
||||
CKMK_MACERR("Signed Failed", cssmErr);
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
if (cssmOutput.Length > output->size) {
|
||||
free(cssmOutput.Data);
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
nsslibc_memcpy(output->data, cssmOutput.Data, cssmOutput.Length);
|
||||
free(cssmOutput.Data);
|
||||
output->size = cssmOutput.Length;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation
|
||||
ckmk_mdCryptoOperationRSADecrypt_proto = {
|
||||
NULL, /* etc */
|
||||
ckmk_mdCryptoOperationRSAPriv_Destroy,
|
||||
NULL, /* GetFinalLengh - not needed for one shot Decrypt/Encrypt */
|
||||
ckmk_mdCryptoOperationRSADecrypt_GetOperationLength,
|
||||
NULL, /* Final - not needed for one shot operation */
|
||||
NULL, /* Update - not needed for one shot operation */
|
||||
NULL, /* DigetUpdate - not needed for one shot operation */
|
||||
ckmk_mdCryptoOperationRSADecrypt_UpdateFinal,
|
||||
NULL, /* UpdateCombo - not needed for one shot operation */
|
||||
NULL, /* DigetKey - not needed for one shot operation */
|
||||
(void *)NULL /* null terminator */
|
||||
};
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation
|
||||
ckmk_mdCryptoOperationRSASign_proto = {
|
||||
NULL, /* etc */
|
||||
ckmk_mdCryptoOperationRSAPriv_Destroy,
|
||||
ckmk_mdCryptoOperationRSA_GetFinalLength,
|
||||
NULL, /* GetOperationLengh - not needed for one shot Sign/Verify */
|
||||
NULL, /* Final - not needed for one shot operation */
|
||||
NULL, /* Update - not needed for one shot operation */
|
||||
NULL, /* DigetUpdate - not needed for one shot operation */
|
||||
ckmk_mdCryptoOperationRSASign_UpdateFinal,
|
||||
NULL, /* UpdateCombo - not needed for one shot operation */
|
||||
NULL, /* DigetKey - not needed for one shot operation */
|
||||
(void *)NULL /* null terminator */
|
||||
};
|
||||
|
||||
/********** NSSCKMDMechansim functions ***********************/
|
||||
/*
|
||||
* ckmk_mdMechanismRSA_Destroy
|
||||
*/
|
||||
static void
|
||||
ckmk_mdMechanismRSA_Destroy(
|
||||
NSSCKMDMechanism *mdMechanism,
|
||||
NSSCKFWMechanism *fwMechanism,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
nss_ZFreeIf(fwMechanism);
|
||||
}
|
||||
|
||||
/*
|
||||
* ckmk_mdMechanismRSA_GetMinKeySize
|
||||
*/
|
||||
static CK_ULONG
|
||||
ckmk_mdMechanismRSA_GetMinKeySize(
|
||||
NSSCKMDMechanism *mdMechanism,
|
||||
NSSCKFWMechanism *fwMechanism,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return 384;
|
||||
}
|
||||
|
||||
/*
|
||||
* ckmk_mdMechanismRSA_GetMaxKeySize
|
||||
*/
|
||||
static CK_ULONG
|
||||
ckmk_mdMechanismRSA_GetMaxKeySize(
|
||||
NSSCKMDMechanism *mdMechanism,
|
||||
NSSCKFWMechanism *fwMechanism,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return 16384;
|
||||
}
|
||||
|
||||
/*
|
||||
* ckmk_mdMechanismRSA_DecryptInit
|
||||
*/
|
||||
static NSSCKMDCryptoOperation *
|
||||
ckmk_mdMechanismRSA_DecryptInit(
|
||||
NSSCKMDMechanism *mdMechanism,
|
||||
NSSCKFWMechanism *fwMechanism,
|
||||
CK_MECHANISM *pMechanism,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
NSSCKMDObject *mdKey,
|
||||
NSSCKFWObject *fwKey,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return ckmk_mdCryptoOperationRSAPriv_Create(
|
||||
&ckmk_mdCryptoOperationRSADecrypt_proto,
|
||||
mdMechanism, mdKey, CKMK_DECRYPT, pError);
|
||||
}
|
||||
|
||||
/*
|
||||
* ckmk_mdMechanismRSA_SignInit
|
||||
*/
|
||||
static NSSCKMDCryptoOperation *
|
||||
ckmk_mdMechanismRSA_SignInit(
|
||||
NSSCKMDMechanism *mdMechanism,
|
||||
NSSCKFWMechanism *fwMechanism,
|
||||
CK_MECHANISM *pMechanism,
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
NSSCKMDObject *mdKey,
|
||||
NSSCKFWObject *fwKey,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return ckmk_mdCryptoOperationRSAPriv_Create(
|
||||
&ckmk_mdCryptoOperationRSASign_proto,
|
||||
mdMechanism, mdKey, CKMK_SIGN, pError);
|
||||
}
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSCKMDMechanism
|
||||
nss_ckmk_mdMechanismRSA = {
|
||||
(void *)NULL, /* etc */
|
||||
ckmk_mdMechanismRSA_Destroy,
|
||||
ckmk_mdMechanismRSA_GetMinKeySize,
|
||||
ckmk_mdMechanismRSA_GetMaxKeySize,
|
||||
NULL, /* GetInHardware - default false */
|
||||
NULL, /* EncryptInit - default errs */
|
||||
ckmk_mdMechanismRSA_DecryptInit,
|
||||
NULL, /* DigestInit - default errs*/
|
||||
ckmk_mdMechanismRSA_SignInit,
|
||||
NULL, /* VerifyInit - default errs */
|
||||
ckmk_mdMechanismRSA_SignInit, /* SignRecoverInit */
|
||||
NULL, /* VerifyRecoverInit - default errs */
|
||||
NULL, /* GenerateKey - default errs */
|
||||
NULL, /* GenerateKeyPair - default errs */
|
||||
NULL, /* GetWrapKeyLength - default errs */
|
||||
NULL, /* WrapKey - default errs */
|
||||
NULL, /* UnwrapKey - default errs */
|
||||
NULL, /* DeriveKey - default errs */
|
||||
(void *)NULL /* null terminator */
|
||||
};
|
|
@ -1,87 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ckmk.h"
|
||||
|
||||
/*
|
||||
* nssmkey/msession.c
|
||||
*
|
||||
* This file implements the NSSCKMDSession object for the
|
||||
* "nssmkey" cryptoki module.
|
||||
*/
|
||||
|
||||
static NSSCKMDFindObjects *
|
||||
ckmk_mdSession_FindObjectsInit(
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return nss_ckmk_FindObjectsInit(fwSession, pTemplate, ulAttributeCount, pError);
|
||||
}
|
||||
|
||||
static NSSCKMDObject *
|
||||
ckmk_mdSession_CreateObject(
|
||||
NSSCKMDSession *mdSession,
|
||||
NSSCKFWSession *fwSession,
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
NSSArena *arena,
|
||||
CK_ATTRIBUTE_PTR pTemplate,
|
||||
CK_ULONG ulAttributeCount,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return nss_ckmk_CreateObject(fwSession, pTemplate, ulAttributeCount, pError);
|
||||
}
|
||||
|
||||
NSS_IMPLEMENT NSSCKMDSession *
|
||||
nss_ckmk_CreateSession(
|
||||
NSSCKFWSession *fwSession,
|
||||
CK_RV *pError)
|
||||
{
|
||||
NSSArena *arena;
|
||||
NSSCKMDSession *rv;
|
||||
|
||||
arena = NSSCKFWSession_GetArena(fwSession, pError);
|
||||
if ((NSSArena *)NULL == arena) {
|
||||
return (NSSCKMDSession *)NULL;
|
||||
}
|
||||
|
||||
rv = nss_ZNEW(arena, NSSCKMDSession);
|
||||
if ((NSSCKMDSession *)NULL == rv) {
|
||||
*pError = CKR_HOST_MEMORY;
|
||||
return (NSSCKMDSession *)NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* rv was zeroed when allocated, so we only
|
||||
* need to set the non-zero members.
|
||||
*/
|
||||
|
||||
rv->etc = (void *)fwSession;
|
||||
/* rv->Close */
|
||||
/* rv->GetDeviceError */
|
||||
/* rv->Login */
|
||||
/* rv->Logout */
|
||||
/* rv->InitPIN */
|
||||
/* rv->SetPIN */
|
||||
/* rv->GetOperationStateLen */
|
||||
/* rv->GetOperationState */
|
||||
/* rv->SetOperationState */
|
||||
rv->CreateObject = ckmk_mdSession_CreateObject;
|
||||
/* rv->CopyObject */
|
||||
rv->FindObjectsInit = ckmk_mdSession_FindObjectsInit;
|
||||
/* rv->SeedRandom */
|
||||
/* rv->GetRandom */
|
||||
/* rv->null */
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ckmk.h"
|
||||
|
||||
/*
|
||||
* nssmkey/mslot.c
|
||||
*
|
||||
* This file implements the NSSCKMDSlot object for the
|
||||
* "nssmkey" cryptoki module.
|
||||
*/
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdSlot_GetSlotDescription(
|
||||
NSSCKMDSlot *mdSlot,
|
||||
NSSCKFWSlot *fwSlot,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_SlotDescription;
|
||||
}
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdSlot_GetManufacturerID(
|
||||
NSSCKMDSlot *mdSlot,
|
||||
NSSCKFWSlot *fwSlot,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_ManufacturerID;
|
||||
}
|
||||
|
||||
static CK_VERSION
|
||||
ckmk_mdSlot_GetHardwareVersion(
|
||||
NSSCKMDSlot *mdSlot,
|
||||
NSSCKFWSlot *fwSlot,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return nss_ckmk_HardwareVersion;
|
||||
}
|
||||
|
||||
static CK_VERSION
|
||||
ckmk_mdSlot_GetFirmwareVersion(
|
||||
NSSCKMDSlot *mdSlot,
|
||||
NSSCKFWSlot *fwSlot,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return nss_ckmk_FirmwareVersion;
|
||||
}
|
||||
|
||||
static NSSCKMDToken *
|
||||
ckmk_mdSlot_GetToken(
|
||||
NSSCKMDSlot *mdSlot,
|
||||
NSSCKFWSlot *fwSlot,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSCKMDToken *)&nss_ckmk_mdToken;
|
||||
}
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSCKMDSlot
|
||||
nss_ckmk_mdSlot = {
|
||||
(void *)NULL, /* etc */
|
||||
NULL, /* Initialize */
|
||||
NULL, /* Destroy */
|
||||
ckmk_mdSlot_GetSlotDescription,
|
||||
ckmk_mdSlot_GetManufacturerID,
|
||||
NULL, /* GetTokenPresent -- defaults to true */
|
||||
NULL, /* GetRemovableDevice -- defaults to false */
|
||||
NULL, /* GetHardwareSlot -- defaults to false */
|
||||
ckmk_mdSlot_GetHardwareVersion,
|
||||
ckmk_mdSlot_GetFirmwareVersion,
|
||||
ckmk_mdSlot_GetToken,
|
||||
(void *)NULL /* null terminator */
|
||||
};
|
|
@ -1,184 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ckmk.h"
|
||||
|
||||
/*
|
||||
* nssmkey/mtoken.c
|
||||
*
|
||||
* This file implements the NSSCKMDToken object for the
|
||||
* "nssmkey" cryptoki module.
|
||||
*/
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdToken_GetLabel(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_TokenLabel;
|
||||
}
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdToken_GetManufacturerID(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_ManufacturerID;
|
||||
}
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdToken_GetModel(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_TokenModel;
|
||||
}
|
||||
|
||||
static NSSUTF8 *
|
||||
ckmk_mdToken_GetSerialNumber(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return (NSSUTF8 *)nss_ckmk_TokenSerialNumber;
|
||||
}
|
||||
|
||||
static CK_BBOOL
|
||||
ckmk_mdToken_GetIsWriteProtected(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
/* fake out Mozilla so we don't try to initialize the token */
|
||||
static CK_BBOOL
|
||||
ckmk_mdToken_GetUserPinInitialized(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return CK_TRUE;
|
||||
}
|
||||
|
||||
static CK_VERSION
|
||||
ckmk_mdToken_GetHardwareVersion(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return nss_ckmk_HardwareVersion;
|
||||
}
|
||||
|
||||
static CK_VERSION
|
||||
ckmk_mdToken_GetFirmwareVersion(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return nss_ckmk_FirmwareVersion;
|
||||
}
|
||||
|
||||
static NSSCKMDSession *
|
||||
ckmk_mdToken_OpenSession(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
NSSCKFWSession *fwSession,
|
||||
CK_BBOOL rw,
|
||||
CK_RV *pError)
|
||||
{
|
||||
return nss_ckmk_CreateSession(fwSession, pError);
|
||||
}
|
||||
|
||||
static CK_ULONG
|
||||
ckmk_mdToken_GetMechanismCount(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance)
|
||||
{
|
||||
return (CK_ULONG)1;
|
||||
}
|
||||
|
||||
static CK_RV
|
||||
ckmk_mdToken_GetMechanismTypes(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_MECHANISM_TYPE types[])
|
||||
{
|
||||
types[0] = CKM_RSA_PKCS;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static NSSCKMDMechanism *
|
||||
ckmk_mdToken_GetMechanism(
|
||||
NSSCKMDToken *mdToken,
|
||||
NSSCKFWToken *fwToken,
|
||||
NSSCKMDInstance *mdInstance,
|
||||
NSSCKFWInstance *fwInstance,
|
||||
CK_MECHANISM_TYPE which,
|
||||
CK_RV *pError)
|
||||
{
|
||||
if (which != CKM_RSA_PKCS) {
|
||||
*pError = CKR_MECHANISM_INVALID;
|
||||
return (NSSCKMDMechanism *)NULL;
|
||||
}
|
||||
return (NSSCKMDMechanism *)&nss_ckmk_mdMechanismRSA;
|
||||
}
|
||||
|
||||
NSS_IMPLEMENT_DATA const NSSCKMDToken
|
||||
nss_ckmk_mdToken = {
|
||||
(void *)NULL, /* etc */
|
||||
NULL, /* Setup */
|
||||
NULL, /* Invalidate */
|
||||
NULL, /* InitToken -- default errs */
|
||||
ckmk_mdToken_GetLabel,
|
||||
ckmk_mdToken_GetManufacturerID,
|
||||
ckmk_mdToken_GetModel,
|
||||
ckmk_mdToken_GetSerialNumber,
|
||||
NULL, /* GetHasRNG -- default is false */
|
||||
ckmk_mdToken_GetIsWriteProtected,
|
||||
NULL, /* GetLoginRequired -- default is false */
|
||||
ckmk_mdToken_GetUserPinInitialized,
|
||||
NULL, /* GetRestoreKeyNotNeeded -- irrelevant */
|
||||
NULL, /* GetHasClockOnToken -- default is false */
|
||||
NULL, /* GetHasProtectedAuthenticationPath -- default is false */
|
||||
NULL, /* GetSupportsDualCryptoOperations -- default is false */
|
||||
NULL, /* GetMaxSessionCount -- default is CK_UNAVAILABLE_INFORMATION */
|
||||
NULL, /* GetMaxRwSessionCount -- default is CK_UNAVAILABLE_INFORMATION */
|
||||
NULL, /* GetMaxPinLen -- irrelevant */
|
||||
NULL, /* GetMinPinLen -- irrelevant */
|
||||
NULL, /* GetTotalPublicMemory -- default is CK_UNAVAILABLE_INFORMATION */
|
||||
NULL, /* GetFreePublicMemory -- default is CK_UNAVAILABLE_INFORMATION */
|
||||
NULL, /* GetTotalPrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */
|
||||
NULL, /* GetFreePrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */
|
||||
ckmk_mdToken_GetHardwareVersion,
|
||||
ckmk_mdToken_GetFirmwareVersion,
|
||||
NULL, /* GetUTCTime -- no clock */
|
||||
ckmk_mdToken_OpenSession,
|
||||
ckmk_mdToken_GetMechanismCount,
|
||||
ckmk_mdToken_GetMechanismTypes,
|
||||
ckmk_mdToken_GetMechanism,
|
||||
(void *)NULL /* null terminator */
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
;+#
|
||||
;+# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;+# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;+#
|
||||
;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS
|
||||
;+# 1. For all unix platforms, the string ";-" means "remove this line"
|
||||
;+# 2. For all unix platforms, the string " DATA " will be removed from any
|
||||
;+# line on which it occurs.
|
||||
;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
|
||||
;+# On AIX, lines containing ";+" will be removed.
|
||||
;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed.
|
||||
;+# 5. For all unix platforms, after the above processing has taken place,
|
||||
;+# all characters after the first ";" on the line will be removed.
|
||||
;+# And for AIX, the first ";" will also be removed.
|
||||
;+# This file is passed directly to windows. Since ';' is a comment, all UNIX
|
||||
;+# directives are hidden behind ";", ";+", and ";-"
|
||||
;+
|
||||
;+NSSMKEY_3.0 { # First release of nssmkey
|
||||
;+ global:
|
||||
LIBRARY nssmkey ;-
|
||||
EXPORTS ;-
|
||||
C_GetFunctionList;
|
||||
;+ local:
|
||||
;+*;
|
||||
;+};
|
|
@ -1,41 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef NSSMKEY_H
|
||||
#define NSSMKEY_H
|
||||
|
||||
/*
|
||||
* NSS CKMK Version numbers.
|
||||
*
|
||||
* These are the version numbers for the nssmkey module packaged with
|
||||
* this release on NSS. To determine the version numbers of the builtin
|
||||
* module you are using, use the appropriate PKCS #11 calls.
|
||||
*
|
||||
* These version numbers detail changes to the PKCS #11 interface. They map
|
||||
* to the PKCS #11 spec versions.
|
||||
*/
|
||||
#define NSS_CKMK_CRYPTOKI_VERSION_MAJOR 2
|
||||
#define NSS_CKMK_CRYPTOKI_VERSION_MINOR 20
|
||||
|
||||
/* These version numbers detail the changes
|
||||
* to the list of trusted certificates.
|
||||
*
|
||||
* NSS_CKMK_LIBRARY_VERSION_MINOR is a CK_BYTE. It's not clear
|
||||
* whether we may use its full range (0-255) or only 0-99 because
|
||||
* of the comment in the CK_VERSION type definition.
|
||||
*/
|
||||
#define NSS_CKMK_LIBRARY_VERSION_MAJOR 1
|
||||
#define NSS_CKMK_LIBRARY_VERSION_MINOR 1
|
||||
#define NSS_CKMK_LIBRARY_VERSION "1.1"
|
||||
|
||||
/* These version numbers detail the semantic changes to the ckfw engine. */
|
||||
#define NSS_CKMK_HARDWARE_VERSION_MAJOR 1
|
||||
#define NSS_CKMK_HARDWARE_VERSION_MINOR 0
|
||||
|
||||
/* These version numbers detail the semantic changes to ckbi itself
|
||||
* (new PKCS #11 objects), etc. */
|
||||
#define NSS_CKMK_FIRMWARE_VERSION_MAJOR 1
|
||||
#define NSS_CKMK_FIRMWARE_VERSION_MINOR 0
|
||||
|
||||
#endif /* NSSMKEY_H */
|
|
@ -1,36 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CKMK_H
|
||||
#include "ckmk.h"
|
||||
#endif /* CKMK_H */
|
||||
|
||||
static const CK_TRUST ckt_netscape_valid = CKT_NETSCAPE_VALID;
|
||||
static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
|
||||
static const CK_TRUST ckt_netscape_trusted_delegator = CKT_NETSCAPE_TRUSTED_DELEGATOR;
|
||||
static const CK_OBJECT_CLASS cko_netscape_trust = CKO_NETSCAPE_TRUST;
|
||||
static const CK_BBOOL ck_true = CK_TRUE;
|
||||
static const CK_OBJECT_CLASS cko_data = CKO_DATA;
|
||||
static const CK_CERTIFICATE_TYPE ckc_x_509 = CKC_X_509;
|
||||
static const CK_BBOOL ck_false = CK_FALSE;
|
||||
static const CK_OBJECT_CLASS cko_netscape_builtin_root_list = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
|
||||
|
||||
/* example of a static object */
|
||||
static const CK_ATTRIBUTE_TYPE nss_ckmk_types_1[] = {
|
||||
CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_LABEL
|
||||
};
|
||||
|
||||
static const NSSItem nss_ckmk_items_1[] = {
|
||||
{ (void *)&cko_data, (PRUint32)sizeof(CK_OBJECT_CLASS) },
|
||||
{ (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) },
|
||||
{ (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) },
|
||||
{ (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) },
|
||||
{ (void *)"Mozilla Mac Key Ring Access", (PRUint32)28 }
|
||||
};
|
||||
|
||||
ckmkInternalObject nss_ckmk_data[] = {
|
||||
{ ckmkRaw, { { 5, nss_ckmk_types_1, nss_ckmk_items_1 } }, CKO_DATA, { NULL } },
|
||||
};
|
||||
|
||||
const PRUint32 nss_ckmk_nObjects = 1;
|
|
@ -16,14 +16,11 @@
|
|||
#include "blapi.h"
|
||||
#include "nssilock.h"
|
||||
#include "secitem.h"
|
||||
#include "blapi.h"
|
||||
#include "blapit.h"
|
||||
#include "mpi.h"
|
||||
#include "secmpi.h"
|
||||
#include "pqg.h"
|
||||
|
||||
/* XXX to be replaced by define in blapit.h */
|
||||
#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
|
||||
|
||||
/*
|
||||
* FIPS 186-2 requires result from random output to be reduced mod q when
|
||||
* generating random numbers for DSA.
|
||||
|
@ -168,7 +165,7 @@ dsa_NewKeyExtended(const PQGParams *params, const SECItem *seed,
|
|||
return SECFailure;
|
||||
}
|
||||
/* Initialize an arena for the DSA key. */
|
||||
arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE);
|
||||
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
|
||||
if (!arena) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
return SECFailure;
|
||||
|
@ -213,8 +210,9 @@ cleanup:
|
|||
mp_clear(&g);
|
||||
mp_clear(&x);
|
||||
mp_clear(&y);
|
||||
if (key)
|
||||
if (key) {
|
||||
PORT_FreeArena(key->params.arena, PR_TRUE);
|
||||
}
|
||||
if (err) {
|
||||
translate_mpi_error(err);
|
||||
return SECFailure;
|
||||
|
@ -321,6 +319,7 @@ dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
|
|||
mp_int x, k; /* private key & pseudo-random integer */
|
||||
mp_int r, s; /* tuple (r, s) is signature) */
|
||||
mp_int t; /* holding tmp values */
|
||||
mp_int ar; /* holding blinding values */
|
||||
mp_err err = MP_OKAY;
|
||||
SECStatus rv = SECSuccess;
|
||||
unsigned int dsa_subprime_len, dsa_signature_len, offset;
|
||||
|
@ -364,6 +363,7 @@ dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
|
|||
MP_DIGITS(&r) = 0;
|
||||
MP_DIGITS(&s) = 0;
|
||||
MP_DIGITS(&t) = 0;
|
||||
MP_DIGITS(&ar) = 0;
|
||||
CHECK_MPI_OK(mp_init(&p));
|
||||
CHECK_MPI_OK(mp_init(&q));
|
||||
CHECK_MPI_OK(mp_init(&g));
|
||||
|
@ -372,6 +372,7 @@ dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
|
|||
CHECK_MPI_OK(mp_init(&r));
|
||||
CHECK_MPI_OK(mp_init(&s));
|
||||
CHECK_MPI_OK(mp_init(&t));
|
||||
CHECK_MPI_OK(mp_init(&ar));
|
||||
/*
|
||||
** Convert stored PQG and private key into MPI integers.
|
||||
*/
|
||||
|
@ -397,14 +398,28 @@ dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
|
|||
rv = SECFailure;
|
||||
goto cleanup;
|
||||
}
|
||||
SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */
|
||||
SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */
|
||||
SECITEM_FreeItem(&t2, PR_FALSE);
|
||||
if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_NEED_RANDOM);
|
||||
rv = SECFailure;
|
||||
goto cleanup;
|
||||
}
|
||||
SECITEM_TO_MPINT(t2, &ar); /* ar <-$ Zq */
|
||||
SECITEM_FreeItem(&t2, PR_FALSE);
|
||||
|
||||
/* Using mp_invmod on k directly would leak bits from k. */
|
||||
CHECK_MPI_OK(mp_mul(&k, &ar, &k)); /* k = k * ar */
|
||||
CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
|
||||
CHECK_MPI_OK(mp_invmod(&k, &q, &k)); /* k = k**-1 mod q */
|
||||
CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
|
||||
SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */
|
||||
CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */
|
||||
CHECK_MPI_OK(mp_addmod(&s, &x, &q, &s)); /* s = s + x mod q */
|
||||
CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */
|
||||
/* To avoid leaking secret bits here the addition is blinded. */
|
||||
CHECK_MPI_OK(mp_mul(&x, &ar, &x)); /* x = x * ar */
|
||||
CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */
|
||||
CHECK_MPI_OK(mp_mulmod(&s, &ar, &q, &t)); /* t = s * ar mod q */
|
||||
CHECK_MPI_OK(mp_add(&t, &x, &s)); /* s = t + x */
|
||||
CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */
|
||||
/*
|
||||
** verify r != 0 and s != 0
|
||||
** mentioned as optional in FIPS 186-1.
|
||||
|
@ -438,7 +453,7 @@ cleanup:
|
|||
mp_clear(&r);
|
||||
mp_clear(&s);
|
||||
mp_clear(&t);
|
||||
SECITEM_FreeItem(&t2, PR_FALSE);
|
||||
mp_clear(&ar);
|
||||
if (err) {
|
||||
translate_mpi_error(err);
|
||||
rv = SECFailure;
|
||||
|
|
|
@ -653,6 +653,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
|
|||
mp_int r, s; /* tuple (r, s) is the signature */
|
||||
mp_int t; /* holding tmp values */
|
||||
mp_int n;
|
||||
mp_int ar; /* blinding value */
|
||||
mp_err err = MP_OKAY;
|
||||
ECParams *ecParams = NULL;
|
||||
SECItem kGpoint = { siBuffer, NULL, 0 };
|
||||
|
@ -674,6 +675,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
|
|||
MP_DIGITS(&s) = 0;
|
||||
MP_DIGITS(&n) = 0;
|
||||
MP_DIGITS(&t) = 0;
|
||||
MP_DIGITS(&ar) = 0;
|
||||
|
||||
/* Check args */
|
||||
if (!key || !signature || !digest || !kb || (kblen < 0)) {
|
||||
|
@ -700,6 +702,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
|
|||
CHECK_MPI_OK(mp_init(&s));
|
||||
CHECK_MPI_OK(mp_init(&n));
|
||||
CHECK_MPI_OK(mp_init(&t));
|
||||
CHECK_MPI_OK(mp_init(&ar));
|
||||
|
||||
SECITEM_TO_MPINT(ecParams->order, &n);
|
||||
SECITEM_TO_MPINT(key->privateValue, &d);
|
||||
|
@ -815,12 +818,25 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
|
|||
goto cleanup;
|
||||
}
|
||||
CHECK_MPI_OK(mp_read_unsigned_octets(&t, t2, 2 * ecParams->order.len)); /* t <-$ Zn */
|
||||
CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
|
||||
CHECK_MPI_OK(mp_invmod(&k, &n, &k)); /* k = k**-1 mod n */
|
||||
CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
|
||||
CHECK_MPI_OK(mp_mulmod(&d, &r, &n, &d)); /* d = d * r mod n */
|
||||
CHECK_MPI_OK(mp_addmod(&s, &d, &n, &s)); /* s = s + d mod n */
|
||||
CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s)); /* s = s * k mod n */
|
||||
PORT_Memset(t2, 0, 2 * ecParams->order.len);
|
||||
if (RNG_GenerateGlobalRandomBytes(t2, 2 * ecParams->order.len) != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_NEED_RANDOM);
|
||||
rv = SECFailure;
|
||||
goto cleanup;
|
||||
}
|
||||
CHECK_MPI_OK(mp_read_unsigned_octets(&ar, t2, 2 * ecParams->order.len)); /* ar <-$ Zn */
|
||||
|
||||
/* Using mp_invmod on k directly would leak bits from k. */
|
||||
CHECK_MPI_OK(mp_mul(&k, &ar, &k)); /* k = k * ar */
|
||||
CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
|
||||
CHECK_MPI_OK(mp_invmod(&k, &n, &k)); /* k = k**-1 mod n */
|
||||
CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
|
||||
/* To avoid leaking secret bits here the addition is blinded. */
|
||||
CHECK_MPI_OK(mp_mul(&d, &ar, &t)); /* t = d * ar */
|
||||
CHECK_MPI_OK(mp_mulmod(&t, &r, &n, &d)); /* d = t * r mod n */
|
||||
CHECK_MPI_OK(mp_mulmod(&s, &ar, &n, &t)); /* t = s * ar mod n */
|
||||
CHECK_MPI_OK(mp_add(&t, &d, &s)); /* s = t + d */
|
||||
CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s)); /* s = s * k mod n */
|
||||
|
||||
#if EC_DEBUG
|
||||
mp_todecimal(&s, mpstr);
|
||||
|
@ -858,6 +874,7 @@ cleanup:
|
|||
mp_clear(&s);
|
||||
mp_clear(&n);
|
||||
mp_clear(&t);
|
||||
mp_clear(&ar);
|
||||
|
||||
if (t2) {
|
||||
PORT_Free(t2);
|
||||
|
|
|
@ -884,7 +884,9 @@ sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
|
|||
unsigned int nItems = 0;
|
||||
SECStatus rv;
|
||||
|
||||
if (!safeBag || !p12ctxt) {
|
||||
PORT_Assert(p12ctxt->arena == safeBag->arena);
|
||||
if (!safeBag || !p12ctxt || p12ctxt->arena != safeBag->arena) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
|
@ -1589,6 +1591,7 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
|
|||
params = PK11_CreatePBEParams(salt, &pwd,
|
||||
NSS_PBE_DEFAULT_ITERATION_COUNT);
|
||||
SECITEM_ZfreeItem(salt, PR_TRUE);
|
||||
salt = NULL;
|
||||
SECITEM_ZfreeItem(&pwd, PR_FALSE);
|
||||
|
||||
/* get the PBA Mechanism to generate the key */
|
||||
|
|
|
@ -2577,14 +2577,13 @@ ReadDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
|
|||
SECItem dbentry;
|
||||
SECStatus rv;
|
||||
|
||||
PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if (arena == NULL) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
goto loser;
|
||||
}
|
||||
|
||||
PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
|
||||
|
||||
entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
|
||||
sizeof(certDBEntrySubject));
|
||||
if (entry == NULL) {
|
||||
|
|
|
@ -138,12 +138,14 @@ sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue)
|
|||
SFTKDBEncryptedDataInfo edi;
|
||||
SECStatus rv;
|
||||
|
||||
PORT_Assert(cipherValue);
|
||||
cipherValue->arena = NULL;
|
||||
cipherValue->param = NULL;
|
||||
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if (arena == NULL) {
|
||||
return SECFailure;
|
||||
}
|
||||
cipherValue->arena = NULL;
|
||||
cipherValue->param = NULL;
|
||||
|
||||
rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate,
|
||||
cipherText);
|
||||
|
|
|
@ -724,13 +724,16 @@ dtls_FragmentHandshake(sslSocket *ss, DTLSQueuedMessage *msg)
|
|||
PORT_Assert(end <= contentLen);
|
||||
fragmentLen = PR_MIN(end, contentLen) - fragmentOffset;
|
||||
|
||||
/* Reduce to the space remaining in the MTU. Allow for any existing
|
||||
* messages, record expansion, and the handshake header. */
|
||||
/* Limit further by the record size limit. Account for the header. */
|
||||
fragmentLen = PR_MIN(fragmentLen,
|
||||
msg->cwSpec->recordSizeLimit - DTLS_HS_HDR_LEN);
|
||||
|
||||
/* Reduce to the space remaining in the MTU. */
|
||||
fragmentLen = PR_MIN(fragmentLen,
|
||||
ss->ssl3.mtu - /* MTU estimate. */
|
||||
ss->pendingBuf.len - /* Less unsent records. */
|
||||
ss->pendingBuf.len - /* Less any unsent records. */
|
||||
DTLS_MAX_EXPANSION - /* Allow for expansion. */
|
||||
DTLS_HS_HDR_LEN); /* + handshake header. */
|
||||
DTLS_HS_HDR_LEN); /* And the handshake header. */
|
||||
PORT_Assert(fragmentLen > 0 || fragmentOffset == 0);
|
||||
|
||||
/* Make totally sure that we will fit in the buffer. This should be
|
||||
|
|
|
@ -243,6 +243,28 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
|
|||
*/
|
||||
#define SSL_ENABLE_0RTT_DATA 33
|
||||
|
||||
/* Sets a limit to the size of encrypted records (see
|
||||
* draft-ietf-tls-record-limit). This is the value that is advertised to peers,
|
||||
* not a limit on the size of records that will be created. Setting this value
|
||||
* reduces the size of records that will be received (not sent).
|
||||
*
|
||||
* This limit applies to the plaintext, but the records that appear on the wire
|
||||
* will be bigger. This doesn't include record headers, IVs, block cipher
|
||||
* padding, and authentication tags or MACs.
|
||||
*
|
||||
* NSS always advertises the record size limit extension. If this option is not
|
||||
* set, the extension will contain the maximum allowed size for the selected TLS
|
||||
* version (currently this is 16384 or 2^14 for TLS 1.2 and lower and 16385 for
|
||||
* TLS 1.3).
|
||||
*
|
||||
* By default, NSS creates records that are the maximum size possible, using all
|
||||
* the data that was written by the application. Writes larger than the maximum
|
||||
* are split into maximum sized records, and any remainder (unless
|
||||
* SSL_CBC_RANDOM_IV is enabled and active). If a peer advertises a record size
|
||||
* limit then that value is used instead.
|
||||
*/
|
||||
#define SSL_RECORD_SIZE_LIMIT 34
|
||||
|
||||
/* Enables TLS 1.3 compatibility mode. In this mode, the client includes a fake
|
||||
* session ID in the handshake and sends a ChangeCipherSpec. A server will
|
||||
* always use the setting chosen by the client, so the value of this option has
|
||||
|
|
|
@ -1476,6 +1476,13 @@ ssl3_SetupBothPendingCipherSpecs(sslSocket *ss)
|
|||
goto loser;
|
||||
}
|
||||
|
||||
if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
|
||||
ss->ssl3.prSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
|
||||
ss->opt.recordSizeLimit);
|
||||
ss->ssl3.pwSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
|
||||
ss->xtnData.recordSizeLimit);
|
||||
}
|
||||
|
||||
ssl_ReleaseSpecWriteLock(ss); /*******************************/
|
||||
return SECSuccess;
|
||||
|
||||
|
@ -2272,7 +2279,7 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type,
|
|||
unsigned int spaceNeeded;
|
||||
SECStatus rv;
|
||||
|
||||
contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
|
||||
contentLen = PR_MIN(nIn, spec->recordSizeLimit);
|
||||
spaceNeeded = contentLen + SSL3_BUFFER_FUDGE;
|
||||
if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
|
||||
spec->cipherDef->type == type_block) {
|
||||
|
@ -12147,6 +12154,11 @@ ssl3_GetCipherSpec(sslSocket *ss, SSL3Ciphertext *cText)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* MAX_EXPANSION is the amount by which a record might plausibly be expanded
|
||||
* when protected. It's the worst case estimate, so the sum of block cipher
|
||||
* padding (up to 256 octets) and HMAC (48 octets for SHA-384). */
|
||||
#define MAX_EXPANSION (256 + 48)
|
||||
|
||||
/* if cText is non-null, then decipher and check the MAC of the
|
||||
* SSL record from cText->buf (typically gs->inbuf)
|
||||
* into databuf (typically gs->buf), and any previous contents of databuf
|
||||
|
@ -12176,6 +12188,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
|
|||
PRBool isTLS;
|
||||
DTLSEpoch epoch;
|
||||
ssl3CipherSpec *spec = NULL;
|
||||
PRUint16 recordSizeLimit;
|
||||
PRBool outOfOrderSpec = PR_FALSE;
|
||||
SSL3ContentType rType;
|
||||
sslBuffer *plaintext = &ss->gs.buf;
|
||||
|
@ -12230,12 +12243,20 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
if (plaintext->space < MAX_FRAGMENT_LENGTH) {
|
||||
rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
|
||||
recordSizeLimit = spec->recordSizeLimit;
|
||||
if (cText->buf->len > recordSizeLimit + MAX_EXPANSION) {
|
||||
ssl_ReleaseSpecReadLock(ss); /*****************************/
|
||||
SSL3_SendAlert(ss, alert_fatal, record_overflow);
|
||||
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (plaintext->space < recordSizeLimit + MAX_EXPANSION) {
|
||||
rv = sslBuffer_Grow(plaintext, recordSizeLimit + MAX_EXPANSION);
|
||||
if (rv != SECSuccess) {
|
||||
ssl_ReleaseSpecReadLock(ss); /*************************/
|
||||
SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
|
||||
SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048));
|
||||
SSL_GETPID(), ss->fd, recordSizeLimit + MAX_EXPANSION));
|
||||
/* sslBuffer_Grow has set a memory error code. */
|
||||
/* Perhaps we should send an alert. (but we have no memory!) */
|
||||
return SECFailure;
|
||||
|
@ -12294,7 +12315,10 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
|
|||
if (IS_DTLS(ss) ||
|
||||
(ss->sec.isServer &&
|
||||
ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
|
||||
/* Silently drop the packet */
|
||||
/* Silently drop the packet unless we sent a fatal alert. */
|
||||
if (ss->ssl3.fatalAlertSent) {
|
||||
return SECFailure;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -12330,7 +12354,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
|
|||
}
|
||||
|
||||
/* Check the length of the plaintext. */
|
||||
if (isTLS && plaintext->len > MAX_FRAGMENT_LENGTH) {
|
||||
if (isTLS && plaintext->len > recordSizeLimit) {
|
||||
plaintext->len = 0;
|
||||
SSL3_SendAlert(ss, alert_fatal, record_overflow);
|
||||
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
|
||||
|
|
|
@ -50,6 +50,7 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
|
|||
{ ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
|
||||
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
|
||||
{ ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
|
||||
{ ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
@ -68,6 +69,7 @@ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
|
|||
{ ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
|
||||
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
|
||||
{ ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
|
||||
{ ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
@ -134,6 +136,7 @@ static const sslExtensionBuilder clientHelloSendersTLS[] =
|
|||
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
|
||||
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
|
||||
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
|
||||
{ ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn },
|
||||
/* The pre_shared_key extension MUST be last. */
|
||||
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
|
||||
{ 0, NULL }
|
||||
|
|
|
@ -98,6 +98,9 @@ struct TLSExtensionDataStr {
|
|||
/* The application token contains a value that was passed to the client via
|
||||
* a session ticket, or the cookie in a HelloRetryRequest. */
|
||||
SECItem applicationToken;
|
||||
|
||||
/* The record size limit set by the peer. Our value is kept in ss->opt. */
|
||||
PRUint16 recordSizeLimit;
|
||||
};
|
||||
|
||||
typedef struct TLSExtensionStr {
|
||||
|
|
|
@ -1868,3 +1868,67 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
|
|||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
ssl_HandleRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
|
||||
SECItem *data)
|
||||
{
|
||||
SECStatus rv;
|
||||
PRUint32 limit;
|
||||
PRUint32 maxLimit = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)
|
||||
? (MAX_FRAGMENT_LENGTH + 1)
|
||||
: MAX_FRAGMENT_LENGTH;
|
||||
|
||||
rv = ssl3_ExtConsumeHandshakeNumber(ss, &limit, 2, &data->data, &data->len);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (data->len != 0 || limit < 64) {
|
||||
ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
|
||||
PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (ss->sec.isServer) {
|
||||
rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_record_size_limit_xtn,
|
||||
&ssl_SendRecordSizeLimitXtn);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure; /* error already set. */
|
||||
}
|
||||
} else if (limit > maxLimit) {
|
||||
/* The client can sensibly check the maximum. */
|
||||
ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
|
||||
PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* We can't enforce the maximum on a server. But we do need to ensure
|
||||
* that we don't apply a limit that is too large. */
|
||||
xtnData->recordSizeLimit = PR_MIN(maxLimit, limit);
|
||||
xtnData->negotiated[xtnData->numNegotiated++] = ssl_record_size_limit_xtn;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
ssl_SendRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
|
||||
sslBuffer *buf, PRBool *added)
|
||||
{
|
||||
PRUint32 maxLimit;
|
||||
if (ss->sec.isServer) {
|
||||
maxLimit = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)
|
||||
? (MAX_FRAGMENT_LENGTH + 1)
|
||||
: MAX_FRAGMENT_LENGTH;
|
||||
} else {
|
||||
maxLimit = (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3)
|
||||
? (MAX_FRAGMENT_LENGTH + 1)
|
||||
: MAX_FRAGMENT_LENGTH;
|
||||
}
|
||||
PRUint32 limit = PR_MIN(ss->opt.recordSizeLimit, maxLimit);
|
||||
SECStatus rv = sslBuffer_AppendNumber(buf, limit, 2);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
*added = PR_TRUE;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
|
|
@ -119,4 +119,11 @@ SECStatus ssl_SendSupportedGroupsXtn(const sslSocket *ss,
|
|||
SECStatus ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
|
||||
TLSExtensionData *xtnData,
|
||||
sslBuffer *buf, PRBool *added);
|
||||
SECStatus ssl_HandleRecordSizeLimitXtn(const sslSocket *ss,
|
||||
TLSExtensionData *xtnData,
|
||||
SECItem *data);
|
||||
SECStatus ssl_SendRecordSizeLimitXtn(const sslSocket *ss,
|
||||
TLSExtensionData *xtnData,
|
||||
sslBuffer *buf, PRBool *added);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -236,6 +236,7 @@ typedef struct sslOptionsStr {
|
|||
/* If SSL_SetNextProtoNego has been called, then this contains the
|
||||
* list of supported protocols. */
|
||||
SECItem nextProtoNego;
|
||||
PRUint16 recordSizeLimit;
|
||||
|
||||
PRUint32 maxEarlyDataSize;
|
||||
unsigned int useSecurity : 1;
|
||||
|
|
|
@ -55,6 +55,7 @@ static const sslSocketOps ssl_secure_ops = { /* SSL. */
|
|||
static sslOptions ssl_defaults = {
|
||||
.nextProtoNego = { siBuffer, NULL, 0 },
|
||||
.maxEarlyDataSize = 1 << 16,
|
||||
.recordSizeLimit = MAX_FRAGMENT_LENGTH + 1,
|
||||
.useSecurity = PR_TRUE,
|
||||
.useSocks = PR_FALSE,
|
||||
.requestCertificate = PR_FALSE,
|
||||
|
@ -803,6 +804,15 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
|
|||
ss->opt.enable0RttData = val;
|
||||
break;
|
||||
|
||||
case SSL_RECORD_SIZE_LIMIT:
|
||||
if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
rv = SECFailure;
|
||||
} else {
|
||||
ss->opt.recordSizeLimit = val;
|
||||
}
|
||||
break;
|
||||
|
||||
case SSL_ENABLE_TLS13_COMPAT_MODE:
|
||||
ss->opt.enableTls13CompatMode = val;
|
||||
break;
|
||||
|
@ -944,6 +954,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
|
|||
case SSL_ENABLE_0RTT_DATA:
|
||||
val = ss->opt.enable0RttData;
|
||||
break;
|
||||
case SSL_RECORD_SIZE_LIMIT:
|
||||
val = ss->opt.recordSizeLimit;
|
||||
break;
|
||||
case SSL_ENABLE_TLS13_COMPAT_MODE:
|
||||
val = ss->opt.enableTls13CompatMode;
|
||||
break;
|
||||
|
@ -1067,6 +1080,9 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
|
|||
case SSL_ENABLE_0RTT_DATA:
|
||||
val = ssl_defaults.enable0RttData;
|
||||
break;
|
||||
case SSL_RECORD_SIZE_LIMIT:
|
||||
val = ssl_defaults.recordSizeLimit;
|
||||
break;
|
||||
case SSL_ENABLE_TLS13_COMPAT_MODE:
|
||||
val = ssl_defaults.enableTls13CompatMode;
|
||||
break;
|
||||
|
@ -1252,6 +1268,14 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
|
|||
ssl_defaults.enable0RttData = val;
|
||||
break;
|
||||
|
||||
case SSL_RECORD_SIZE_LIMIT:
|
||||
if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
ssl_defaults.recordSizeLimit = val;
|
||||
break;
|
||||
|
||||
case SSL_ENABLE_TLS13_COMPAT_MODE:
|
||||
ssl_defaults.enableTls13CompatMode = val;
|
||||
break;
|
||||
|
|
|
@ -143,6 +143,7 @@ ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction)
|
|||
spec->refCt = 1;
|
||||
spec->version = ss->version;
|
||||
spec->direction = direction;
|
||||
spec->recordSizeLimit = MAX_FRAGMENT_LENGTH;
|
||||
SSL_TRC(10, ("%d: SSL[%d]: new %s spec %d ct=%d",
|
||||
SSL_GETPID(), ss->fd, SPEC_DIR(spec), spec,
|
||||
spec->refCt));
|
||||
|
|
|
@ -170,6 +170,10 @@ struct ssl3CipherSpecStr {
|
|||
/* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
|
||||
* will be zero for everything but 0-RTT. */
|
||||
PRUint32 earlyDataRemaining;
|
||||
/* The maximum plaintext length. This differs from the configured or
|
||||
* negotiated value for TLS 1.3; it is reduced by one to account for the
|
||||
* content type octet. */
|
||||
PRUint16 recordSizeLimit;
|
||||
};
|
||||
|
||||
typedef void (*sslCipherSpecChangedFunc)(void *arg,
|
||||
|
|
|
@ -432,6 +432,7 @@ typedef enum {
|
|||
ssl_signed_cert_timestamp_xtn = 18,
|
||||
ssl_padding_xtn = 21,
|
||||
ssl_extended_master_secret_xtn = 23,
|
||||
ssl_record_size_limit_xtn = 28,
|
||||
ssl_session_ticket_xtn = 35,
|
||||
/* 40 was used in draft versions of TLS 1.3; it is now reserved. */
|
||||
ssl_tls13_pre_shared_key_xtn = 41,
|
||||
|
@ -454,7 +455,7 @@ typedef enum {
|
|||
/* SSL_MAX_EXTENSIONS includes the maximum number of extensions that are
|
||||
* supported for any single message type. That is, a ClientHello; ServerHello
|
||||
* and TLS 1.3 NewSessionTicket and HelloRetryRequest extensions have fewer. */
|
||||
#define SSL_MAX_EXTENSIONS 20
|
||||
#define SSL_MAX_EXTENSIONS 21
|
||||
|
||||
/* Deprecated */
|
||||
typedef enum {
|
||||
|
|
|
@ -3254,6 +3254,17 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
|
|||
}
|
||||
|
||||
tls13_SetSpecRecordVersion(ss, spec);
|
||||
|
||||
/* The record size limit is reduced by one so that the remainder of the
|
||||
* record handling code can use the same checks for all versions. */
|
||||
if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
|
||||
spec->recordSizeLimit = ((spec->direction == CipherSpecRead)
|
||||
? ss->opt.recordSizeLimit
|
||||
: ss->xtnData.recordSizeLimit) -
|
||||
1;
|
||||
} else {
|
||||
spec->recordSizeLimit = MAX_FRAGMENT_LENGTH;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -4746,7 +4757,8 @@ static const struct {
|
|||
{ ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
|
||||
{ ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
|
||||
{ ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
|
||||
hello_retry_request) }
|
||||
hello_retry_request) },
|
||||
{ ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) }
|
||||
};
|
||||
|
||||
tls13ExtensionStatus
|
||||
|
@ -5015,6 +5027,16 @@ tls13_UnprotectRecord(sslSocket *ss,
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
/* There is a similar test in ssl3_HandleRecord, but this test is needed to
|
||||
* account for padding. It's safe to do this here (including the alert),
|
||||
* because it only confirms that the record exceeded the size limit, which
|
||||
* is apparent from the size of the ciphertext. */
|
||||
if (plaintext->len > spec->recordSizeLimit + 1) {
|
||||
SSL3_SendAlert(ss, alert_fatal, record_overflow);
|
||||
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* The record is right-padded with 0s, followed by the true
|
||||
* content type, so read from the right until we receive a
|
||||
* nonzero byte. */
|
||||
|
|
|
@ -32,7 +32,7 @@ bitflags = "1.0"
|
|||
byteorder = "1.0"
|
||||
cfg-if = "0.1.0"
|
||||
cssparser = "0.23.0"
|
||||
debug_unreachable = "0.1.1"
|
||||
new_debug_unreachable = "1.0"
|
||||
encoding_rs = {version = "0.7", optional = true}
|
||||
euclid = "0.17"
|
||||
fallible = { path = "../fallible" }
|
||||
|
@ -50,7 +50,7 @@ nsstring = {path = "../../support/gecko/nsstring", optional = true}
|
|||
num_cpus = {version = "1.1.0", optional = true}
|
||||
num-integer = "0.1.32"
|
||||
num-traits = "0.1.32"
|
||||
ordered-float = "0.4"
|
||||
new-ordered-float = "1.0"
|
||||
owning_ref = "0.3.3"
|
||||
parking_lot = "0.5"
|
||||
precomputed-hash = "0.1.1"
|
||||
|
|
|
@ -31,10 +31,11 @@ use values::CSSFloat;
|
|||
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
||||
use values::animated::color::RGBA as AnimatedRGBA;
|
||||
use values::animated::effects::Filter as AnimatedFilter;
|
||||
#[cfg(feature = "gecko")] use values::computed::TransitionProperty;
|
||||
use values::computed::{Angle, CalcLengthOrPercentage};
|
||||
use values::computed::{ClipRect, Context};
|
||||
use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
use values::computed::{LengthOrPercentageOrNone, MaxLength, TransitionProperty};
|
||||
use values::computed::{LengthOrPercentageOrNone, MaxLength};
|
||||
use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
|
||||
use values::computed::length::NonNegativeLengthOrPercentage;
|
||||
use values::computed::ToComputedValue;
|
||||
|
|
|
@ -19,7 +19,8 @@ ${helpers.predefined_type(
|
|||
animation_value_type="discrete",
|
||||
flags="APPLIES_TO_PLACEHOLDER",
|
||||
spec="https://drafts.csswg.org/css-display/#propdef-display",
|
||||
servo_restyle_damage="rebuild_and_reflow"
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
needs_context=product == "gecko"
|
||||
)}
|
||||
|
||||
// FIXME(emilio): Listing all the display values here is very unfortunate, we should teach C++ to use the
|
||||
|
|
|
@ -2501,6 +2501,7 @@ pub mod style_structs {
|
|||
/// Whether this is a multicol style.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn is_multicol(&self) -> bool {
|
||||
use values::Either;
|
||||
match self.column_width {
|
||||
Either::First(_width) => true,
|
||||
Either::Second(_auto) => !self.column_count.is_auto(),
|
||||
|
@ -2699,6 +2700,26 @@ impl ComputedValues {
|
|||
|
||||
/// Get the initial computed values.
|
||||
pub fn initial_values() -> &'static Self { &*INITIAL_SERVO_VALUES }
|
||||
|
||||
/// Serializes the computed value of this property as a string.
|
||||
pub fn computed_value_to_string(&self, property: PropertyDeclarationId) -> String {
|
||||
match property {
|
||||
PropertyDeclarationId::Longhand(id) => {
|
||||
let mut s = String::new();
|
||||
self.get_longhand_property_value(
|
||||
id,
|
||||
&mut CssWriter::new(&mut s)
|
||||
).unwrap();
|
||||
s
|
||||
}
|
||||
PropertyDeclarationId::Custom(name) => {
|
||||
self.custom_properties
|
||||
.as_ref()
|
||||
.and_then(|map| map.get(name))
|
||||
.map_or(String::new(), |value| value.to_css_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
|
@ -2937,26 +2958,6 @@ impl ComputedValuesInner {
|
|||
// Neither perspective nor transform present
|
||||
false
|
||||
}
|
||||
|
||||
/// Serializes the computed value of this property as a string.
|
||||
pub fn computed_value_to_string(&self, property: PropertyDeclarationId) -> String {
|
||||
match property {
|
||||
PropertyDeclarationId::Longhand(id) => {
|
||||
let mut s = String::new();
|
||||
self.get_longhand_property_value(
|
||||
property,
|
||||
&mut CssWriter::new(&mut s)
|
||||
).unwrap();
|
||||
s
|
||||
}
|
||||
PropertyDeclarationId::Custom(name) => {
|
||||
self.custom_properties
|
||||
.as_ref()
|
||||
.and_then(|map| map.get(name))
|
||||
.map_or(String::new(), |value| value.to_css_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
% if product == "gecko":
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use app_units::Au;
|
||||
use logical_geometry::WritingMode;
|
||||
use ordered_float::NotNaN;
|
||||
use ordered_float::NotNan;
|
||||
use properties::LonghandId;
|
||||
use std::fmt::{self, Write};
|
||||
use std::ops::{Add, Neg};
|
||||
|
@ -391,14 +391,14 @@ impl LengthOrPercentage {
|
|||
// CSSFloat doesn't implement Hash, so does CSSPixelLength. Therefore, we still use Au as the
|
||||
// hash key.
|
||||
#[allow(missing_docs)]
|
||||
pub fn to_hash_key(&self) -> (Au, NotNaN<f32>) {
|
||||
pub fn to_hash_key(&self) -> (Au, NotNan<f32>) {
|
||||
use self::LengthOrPercentage::*;
|
||||
match *self {
|
||||
Length(l) => (Au::from(l), NotNaN::new(0.0).unwrap()),
|
||||
Percentage(p) => (Au(0), NotNaN::new(p.0).unwrap()),
|
||||
Length(l) => (Au::from(l), NotNan::new(0.0).unwrap()),
|
||||
Percentage(p) => (Au(0), NotNan::new(p.0).unwrap()),
|
||||
Calc(c) => (
|
||||
Au::from(c.unclamped_length()),
|
||||
NotNaN::new(c.percentage()).unwrap(),
|
||||
NotNan::new(c.percentage()).unwrap(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cg;
|
||||
use parse::ParseVariantAttrs;
|
||||
use quote::Tokens;
|
||||
use syn::{Data, DeriveInput, Fields, Ident, Type};
|
||||
use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs};
|
||||
use parse::ParseVariantAttrs;
|
||||
|
||||
pub fn derive(mut input: DeriveInput) -> Tokens {
|
||||
let css_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"d91d0d75087934c2d0503a8c04439fea459a19182021bb0b699644d442f5b6fc","Cargo.toml":"f6be96c7687e8e39cffc3f22aff16d12d669a31e932c1b98ba590dbaa181ab22","README.md":"0311a4ecf6dd300c555ef0f2316e4ba919476782b6aed1c35b01d8cc2f958c72","examples/simple.rs":"c05b124bdad67bfe9e48998bff6a7c6a8789e7f7c9fb3f318f8028a68ef944ed","src/lib.rs":"ef4e6d5732fcad9da5a500f401ccd0b538b489ae50771d15d5a2ec0f501cd0f9","tests/check.rs":"ac8691f78269e1cb0cd010150e707f5ea5df14055883f0ee5a5b55a686c5b8de"},"package":"9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"}
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
|
||||
name = "debug_unreachable"
|
||||
version = "0.1.1"
|
||||
authors = ["Jonathan Reem <jonathan.reem@gmail.com>"]
|
||||
repository = "https://github.com/reem/rust-debug-unreachable.git"
|
||||
description = "unreachable!() in debug, std::intrinsics::unreachable() in release."
|
||||
documentation = "https://crates.fyi/crates/debug_unreachable/0.1.1"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "debug_unreachable"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
unreachable = "0.1"
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# debug_unreachable
|
||||
|
||||
> unreachable!() in debug, std::intrinsics::unreachable() in release.
|
||||
|
||||
## [Documentation](https://crates.fyi/crates/debug_unreachable/0.1.1)
|
||||
|
||||
## Usage
|
||||
|
||||
Use the crates.io repository; add this to your `Cargo.toml` along
|
||||
with the rest of your dependencies:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
debug_unreachable = "0.1"
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
[Jonathan Reem](https://medium.com/@jreem) is the primary author and maintainer of debug-unreachable.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"files":{".travis.yml":"b828951788f67d00e3869f32b15076dcd8b64d71889c9dacda339571d7da93ac","Cargo.toml":"b2d65471546d2c240fcc7522e68967a5ec9d13bf829dffd708a55739ef337a28","LICENSE-MIT":"f7715d38a3fa1b4ac97c5729740752505a39cb92ee83ab5b102aeb5eaa7cdea4","README.md":"53364727f8bdc8dac2f5a55e7b9741981b757ba5b9331e3ac8ed433b09ee2409","src/lib.rs":"a1fd03bd7601b842b60a94c6161c436befaf25b38f74b247a20e90c24fb2bd9f","tests/test.rs":"1bbfc79ee6e1ffa3fcc384e9ce1f5a9000a63a8ddbc84264caba0454d657f40a","tests/test_deprecated_names.rs":"6f661c27e8b4d625c02202895f220d573e3dccc8cf684c77e754c444403939f7"},"package":"8ccbebba6fb53a6d2bdcfaf79cb339bc136dee3bfff54dc337a334bafe36476a"}
|
|
@ -5,7 +5,5 @@ env:
|
|||
matrix:
|
||||
- FEATURES=
|
||||
- FEATURES="serde"
|
||||
- FEATURES="rustc-serialize"
|
||||
- FEATURES="serde rustc-serialize"
|
||||
script:
|
||||
- cargo test -v --features "$FEATURES"
|
|
@ -0,0 +1,34 @@
|
|||
# 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 = "new-ordered-float"
|
||||
version = "1.0.1"
|
||||
authors = ["Jonathan Reem <jonathan.reem@gmail.com>", "Matt Brubeck <mbrubeck@limpet.net>"]
|
||||
description = "Wrappers for total ordering on floats (fork of ordered-float)"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/mbrubeck/rust-ordered-float"
|
||||
|
||||
[lib]
|
||||
name = "ordered_float"
|
||||
[dependencies.num-traits]
|
||||
version = "0.2"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.unreachable]
|
||||
version = "1"
|
||||
[dev-dependencies.serde_test]
|
||||
version = "1.0"
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2015 Jonathan Reem
|
||||
|
||||
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.
|
|
@ -0,0 +1,27 @@
|
|||
# Ordered Floats
|
||||
|
||||
Provides several wrapper types for Ord and Eq implementations on f64.
|
||||
|
||||
This is a fork of https://crates.io/crates/ordered-float
|
||||
|
||||
## Usage
|
||||
|
||||
Use the crates.io repository; add this to your `Cargo.toml` along
|
||||
with the rest of your dependencies:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
new-ordered-float = "1.0"
|
||||
```
|
||||
|
||||
In your Rust code, the library name is still `ordered_float`:
|
||||
|
||||
```rust
|
||||
extern crate ordered_float;
|
||||
```
|
||||
|
||||
See the [API documentation](https://docs.rs/new-ordered-float) for further details.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
|
@ -15,7 +15,18 @@ use std::fmt;
|
|||
use std::io;
|
||||
use std::mem;
|
||||
use unreachable::unreachable;
|
||||
use num_traits::Float;
|
||||
use num_traits::{Bounded, Float, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive,
|
||||
Zero};
|
||||
|
||||
/// A wrapper around Floats providing an implementation of Ord and Hash.
|
||||
///
|
||||
/// A NaN value cannot be stored in this type.
|
||||
#[deprecated(since = "0.6.0", note = "renamed to `NotNan`")]
|
||||
pub type NotNaN<T> = NotNan<T>;
|
||||
|
||||
/// An error indicating an attempt to construct NotNan from a NaN
|
||||
#[deprecated(since = "0.6.0", note = "renamed to `FloatIsNan`")]
|
||||
pub type FloatIsNaN = FloatIsNan;
|
||||
|
||||
// masks for the parts of the IEEE 754 float
|
||||
const SIGN_MASK: u64 = 0x8000000000000000u64;
|
||||
|
@ -30,7 +41,7 @@ const CANONICAL_ZERO_BITS: u64 = 0x0u64;
|
|||
///
|
||||
/// NaN is sorted as *greater* than all other values and *equal*
|
||||
/// to itself, in contradiction with the IEEE standard.
|
||||
#[derive(PartialOrd, Debug, Default, Clone, Copy)]
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct OrderedFloat<T: Float>(pub T);
|
||||
|
||||
impl<T: Float> OrderedFloat<T> {
|
||||
|
@ -55,13 +66,21 @@ impl<T: Float> AsMut<T> for OrderedFloat<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float + PartialOrd> Ord for OrderedFloat<T> {
|
||||
fn cmp(&self, other: &OrderedFloat<T>) -> Ordering {
|
||||
match self.partial_cmp(&other) {
|
||||
impl<T: Float> PartialOrd for OrderedFloat<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Ord for OrderedFloat<T> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let lhs = self.as_ref();
|
||||
let rhs = other.as_ref();
|
||||
match lhs.partial_cmp(&rhs) {
|
||||
Some(ordering) => ordering,
|
||||
None => {
|
||||
if self.as_ref().is_nan() {
|
||||
if other.as_ref().is_nan() {
|
||||
if lhs.is_nan() {
|
||||
if rhs.is_nan() {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Greater
|
||||
|
@ -77,7 +96,7 @@ impl<T: Float + PartialOrd> Ord for OrderedFloat<T> {
|
|||
impl<T: Float + PartialEq> PartialEq for OrderedFloat<T> {
|
||||
fn eq(&self, other: &OrderedFloat<T>) -> bool {
|
||||
if self.as_ref().is_nan() {
|
||||
if other.as_ref().is_nan() { true } else { false }
|
||||
other.as_ref().is_nan()
|
||||
} else if other.as_ref().is_nan() {
|
||||
false
|
||||
} else {
|
||||
|
@ -141,43 +160,43 @@ impl<T: Float + PartialEq> Eq for OrderedFloat<T> {}
|
|||
///
|
||||
/// A NaN value cannot be stored in this type.
|
||||
#[derive(PartialOrd, PartialEq, Debug, Default, Clone, Copy)]
|
||||
pub struct NotNaN<T: Float>(T);
|
||||
pub struct NotNan<T: Float>(T);
|
||||
|
||||
impl<T: Float> NotNaN<T> {
|
||||
/// Create a NotNaN value.
|
||||
impl<T: Float> NotNan<T> {
|
||||
/// Create a NotNan value.
|
||||
///
|
||||
/// Returns Err if val is NaN
|
||||
pub fn new(val: T) -> Result<Self, FloatIsNaN> {
|
||||
pub fn new(val: T) -> Result<Self, FloatIsNan> {
|
||||
match val {
|
||||
ref val if val.is_nan() => Err(FloatIsNaN),
|
||||
val => Ok(NotNaN(val)),
|
||||
ref val if val.is_nan() => Err(FloatIsNan),
|
||||
val => Ok(NotNan(val)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a NotNaN value from a value that is guaranteed to not be NaN
|
||||
/// Create a NotNan value from a value that is guaranteed to not be NaN
|
||||
///
|
||||
/// Behaviour is undefined if `val` is NaN
|
||||
pub unsafe fn unchecked_new(val: T) -> Self {
|
||||
debug_assert!(!val.is_nan());
|
||||
NotNaN(val)
|
||||
NotNan(val)
|
||||
}
|
||||
|
||||
/// Get the value out.
|
||||
pub fn into_inner(self) -> T {
|
||||
let NotNaN(val) = self;
|
||||
let NotNan(val) = self;
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float> AsRef<T> for NotNaN<T> {
|
||||
impl<T: Float> AsRef<T> for NotNan<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
let NotNaN(ref val) = *self;
|
||||
let NotNan(ref val) = *self;
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + PartialOrd> Ord for NotNaN<T> {
|
||||
fn cmp(&self, other: &NotNaN<T>) -> Ordering {
|
||||
impl<T: Float> Ord for NotNan<T> {
|
||||
fn cmp(&self, other: &NotNan<T>) -> Ordering {
|
||||
match self.partial_cmp(&other) {
|
||||
Some(ord) => ord,
|
||||
None => unsafe { unreachable() },
|
||||
|
@ -185,41 +204,41 @@ impl<T: Float + PartialOrd> Ord for NotNaN<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Hash for NotNaN<T> {
|
||||
impl<T: Float> Hash for NotNan<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
hash_float(self.as_ref(), state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + fmt::Display> fmt::Display for NotNaN<T> {
|
||||
impl<T: Float + fmt::Display> fmt::Display for NotNan<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.as_ref().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f32> for NotNaN<f32> {
|
||||
impl Into<f32> for NotNan<f32> {
|
||||
fn into(self) -> f32 {
|
||||
self.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f64> for NotNaN<f64> {
|
||||
impl Into<f64> for NotNan<f64> {
|
||||
fn into(self) -> f64 {
|
||||
self.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a NotNaN value from a Float.
|
||||
/// Creates a NotNan value from a Float.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl<T: Float> From<T> for NotNaN<T> {
|
||||
impl<T: Float> From<T> for NotNan<T> {
|
||||
fn from(v: T) -> Self {
|
||||
assert!(!v.is_nan());
|
||||
NotNaN(v)
|
||||
NotNan(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Deref for NotNaN<T> {
|
||||
impl<T: Float> Deref for NotNan<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -227,36 +246,36 @@ impl<T: Float> Deref for NotNaN<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float + PartialEq> Eq for NotNaN<T> {}
|
||||
impl<T: Float + PartialEq> Eq for NotNan<T> {}
|
||||
|
||||
impl<T: Float> Add for NotNaN<T> {
|
||||
impl<T: Float> Add for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
NotNaN(self.0 + other.0)
|
||||
NotNan(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl<T: Float> Add<T> for NotNaN<T> {
|
||||
impl<T: Float> Add<T> for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: T) -> Self {
|
||||
assert!(!other.is_nan());
|
||||
NotNaN::new(self.0 + other).expect("Addition resulted in NaN")
|
||||
NotNan::new(self.0 + other).expect("Addition resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for NotNaN<f64> {
|
||||
impl AddAssign for NotNan<f64> {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
self.0 += other.0;
|
||||
assert!(!self.0.is_nan(), "Addition resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for NotNaN<f32> {
|
||||
impl AddAssign for NotNan<f32> {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
self.0 += other.0;
|
||||
assert!(!self.0.is_nan(), "Addition resulted in NaN")
|
||||
|
@ -266,7 +285,7 @@ impl AddAssign for NotNaN<f32> {
|
|||
/// Adds a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl AddAssign<f64> for NotNaN<f64> {
|
||||
impl AddAssign<f64> for NotNan<f64> {
|
||||
fn add_assign(&mut self, other: f64) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 += other;
|
||||
|
@ -277,7 +296,7 @@ impl AddAssign<f64> for NotNaN<f64> {
|
|||
/// Adds a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN.
|
||||
impl AddAssign<f32> for NotNaN<f32> {
|
||||
impl AddAssign<f32> for NotNan<f32> {
|
||||
fn add_assign(&mut self, other: f32) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 += other;
|
||||
|
@ -285,34 +304,34 @@ impl AddAssign<f32> for NotNaN<f32> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Sub for NotNaN<T> {
|
||||
impl<T: Float> Sub for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self {
|
||||
NotNaN::new(self.0 - other.0).expect("Subtraction resulted in NaN")
|
||||
NotNan::new(self.0 - other.0).expect("Subtraction resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
/// Subtracts a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl<T: Float> Sub<T> for NotNaN<T> {
|
||||
impl<T: Float> Sub<T> for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: T) -> Self {
|
||||
assert!(!other.is_nan());
|
||||
NotNaN::new(self.0 - other).expect("Subtraction resulted in NaN")
|
||||
NotNan::new(self.0 - other).expect("Subtraction resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for NotNaN<f64> {
|
||||
impl SubAssign for NotNan<f64> {
|
||||
fn sub_assign(&mut self, other: Self) {
|
||||
self.0 -= other.0;
|
||||
assert!(!self.0.is_nan(), "Subtraction resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for NotNaN<f32> {
|
||||
impl SubAssign for NotNan<f32> {
|
||||
fn sub_assign(&mut self, other: Self) {
|
||||
self.0 -= other.0;
|
||||
assert!(!self.0.is_nan(), "Subtraction resulted in NaN")
|
||||
|
@ -322,7 +341,7 @@ impl SubAssign for NotNaN<f32> {
|
|||
/// Subtracts a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl SubAssign<f64> for NotNaN<f64> {
|
||||
impl SubAssign<f64> for NotNan<f64> {
|
||||
fn sub_assign(&mut self, other: f64) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 -= other;
|
||||
|
@ -333,7 +352,7 @@ impl SubAssign<f64> for NotNaN<f64> {
|
|||
/// Subtracts a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl SubAssign<f32> for NotNaN<f32> {
|
||||
impl SubAssign<f32> for NotNan<f32> {
|
||||
fn sub_assign(&mut self, other: f32) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 -= other;
|
||||
|
@ -341,34 +360,34 @@ impl SubAssign<f32> for NotNaN<f32> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Mul for NotNaN<T> {
|
||||
impl<T: Float> Mul for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, other: Self) -> Self {
|
||||
NotNaN::new(self.0 * other.0).expect("Multiplication resulted in NaN")
|
||||
NotNan::new(self.0 * other.0).expect("Multiplication resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiplies a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl<T: Float> Mul<T> for NotNaN<T> {
|
||||
impl<T: Float> Mul<T> for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, other: T) -> Self {
|
||||
assert!(!other.is_nan());
|
||||
NotNaN::new(self.0 * other).expect("Multiplication resulted in NaN")
|
||||
NotNan::new(self.0 * other).expect("Multiplication resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign for NotNaN<f64> {
|
||||
impl MulAssign for NotNan<f64> {
|
||||
fn mul_assign(&mut self, other: Self) {
|
||||
self.0 *= other.0;
|
||||
assert!(!self.0.is_nan(), "Multiplication resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign for NotNaN<f32> {
|
||||
impl MulAssign for NotNan<f32> {
|
||||
fn mul_assign(&mut self, other: Self) {
|
||||
self.0 *= other.0;
|
||||
assert!(!self.0.is_nan(), "Multiplication resulted in NaN")
|
||||
|
@ -378,7 +397,7 @@ impl MulAssign for NotNaN<f32> {
|
|||
/// Multiplies a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN.
|
||||
impl MulAssign<f64> for NotNaN<f64> {
|
||||
impl MulAssign<f64> for NotNan<f64> {
|
||||
fn mul_assign(&mut self, other: f64) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 *= other;
|
||||
|
@ -388,7 +407,7 @@ impl MulAssign<f64> for NotNaN<f64> {
|
|||
/// Multiplies a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl MulAssign<f32> for NotNaN<f32> {
|
||||
impl MulAssign<f32> for NotNan<f32> {
|
||||
fn mul_assign(&mut self, other: f32) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 *= other;
|
||||
|
@ -396,34 +415,34 @@ impl MulAssign<f32> for NotNaN<f32> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Div for NotNaN<T> {
|
||||
impl<T: Float> Div for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, other: Self) -> Self {
|
||||
NotNaN::new(self.0 / other.0).expect("Division resulted in NaN")
|
||||
NotNan::new(self.0 / other.0).expect("Division resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl<T: Float> Div<T> for NotNaN<T> {
|
||||
impl<T: Float> Div<T> for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, other: T) -> Self {
|
||||
assert!(!other.is_nan());
|
||||
NotNaN::new(self.0 / other).expect("Division resulted in NaN")
|
||||
NotNan::new(self.0 / other).expect("Division resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign for NotNaN<f64> {
|
||||
impl DivAssign for NotNan<f64> {
|
||||
fn div_assign(&mut self, other: Self) {
|
||||
self.0 /= other.0;
|
||||
assert!(!self.0.is_nan(), "Division resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign for NotNaN<f32> {
|
||||
impl DivAssign for NotNan<f32> {
|
||||
fn div_assign(&mut self, other: Self) {
|
||||
self.0 /= other.0;
|
||||
assert!(!self.0.is_nan(), "Division resulted in NaN")
|
||||
|
@ -433,7 +452,7 @@ impl DivAssign for NotNaN<f32> {
|
|||
/// Divides a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl DivAssign<f64> for NotNaN<f64> {
|
||||
impl DivAssign<f64> for NotNan<f64> {
|
||||
fn div_assign(&mut self, other: f64) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 /= other;
|
||||
|
@ -444,7 +463,7 @@ impl DivAssign<f64> for NotNaN<f64> {
|
|||
/// Divides a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl DivAssign<f32> for NotNaN<f32> {
|
||||
impl DivAssign<f32> for NotNan<f32> {
|
||||
fn div_assign(&mut self, other: f32) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 /= other;
|
||||
|
@ -452,34 +471,34 @@ impl DivAssign<f32> for NotNaN<f32> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Rem for NotNaN<T> {
|
||||
impl<T: Float> Rem for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn rem(self, other: Self) -> Self {
|
||||
NotNaN::new(self.0 % other.0).expect("Rem resulted in NaN")
|
||||
NotNan::new(self.0 % other.0).expect("Rem resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates `%` with a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl<T: Float> Rem<T> for NotNaN<T> {
|
||||
impl<T: Float> Rem<T> for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn rem(self, other: T) -> Self {
|
||||
assert!(!other.is_nan());
|
||||
NotNaN::new(self.0 % other).expect("Rem resulted in NaN")
|
||||
NotNan::new(self.0 % other).expect("Rem resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign for NotNaN<f64> {
|
||||
impl RemAssign for NotNan<f64> {
|
||||
fn rem_assign(&mut self, other: Self) {
|
||||
self.0 %= other.0;
|
||||
assert!(!self.0.is_nan(), "Rem resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign for NotNaN<f32> {
|
||||
impl RemAssign for NotNan<f32> {
|
||||
fn rem_assign(&mut self, other: Self) {
|
||||
self.0 %= other.0;
|
||||
assert!(!self.0.is_nan(), "Rem resulted in NaN")
|
||||
|
@ -489,7 +508,7 @@ impl RemAssign for NotNaN<f32> {
|
|||
/// Calculates `%=` with a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl RemAssign<f64> for NotNaN<f64> {
|
||||
impl RemAssign<f64> for NotNan<f64> {
|
||||
fn rem_assign(&mut self, other: f64) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 %= other;
|
||||
|
@ -500,7 +519,7 @@ impl RemAssign<f64> for NotNaN<f64> {
|
|||
/// Calculates `%=` with a float directly.
|
||||
///
|
||||
/// Panics if the provided value is NaN or the computation results in NaN
|
||||
impl RemAssign<f32> for NotNaN<f32> {
|
||||
impl RemAssign<f32> for NotNan<f32> {
|
||||
fn rem_assign(&mut self, other: f32) {
|
||||
assert!(!other.is_nan());
|
||||
self.0 %= other;
|
||||
|
@ -508,31 +527,31 @@ impl RemAssign<f32> for NotNaN<f32> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Float> Neg for NotNaN<T> {
|
||||
impl<T: Float> Neg for NotNan<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self {
|
||||
NotNaN::new(-self.0).expect("Negation resulted in NaN")
|
||||
NotNan::new(-self.0).expect("Negation resulted in NaN")
|
||||
}
|
||||
}
|
||||
|
||||
/// An error indicating an attempt to construct NotNaN from a NaN
|
||||
/// An error indicating an attempt to construct NotNan from a NaN
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct FloatIsNaN;
|
||||
pub struct FloatIsNan;
|
||||
|
||||
impl Error for FloatIsNaN {
|
||||
impl Error for FloatIsNan {
|
||||
fn description(&self) -> &str {
|
||||
return "NotNaN constructed with NaN";
|
||||
"NotNan constructed with NaN"
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FloatIsNaN {
|
||||
impl fmt::Display for FloatIsNan {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
<Self as fmt::Debug>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<io::Error> for FloatIsNaN {
|
||||
impl Into<io::Error> for FloatIsNan {
|
||||
fn into(self) -> io::Error {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, self)
|
||||
}
|
||||
|
@ -559,36 +578,104 @@ fn raw_double_bits<F: Float>(f: &F) -> u64 {
|
|||
(man & MAN_MASK) | ((exp_u64 << 52) & EXP_MASK) | ((sign_u64 << 63) & SIGN_MASK)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod impl_rustc {
|
||||
extern crate rustc_serialize;
|
||||
use self::rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
use super::{OrderedFloat, NotNaN};
|
||||
use std::error::Error;
|
||||
use num_traits::Float;
|
||||
impl<T: Float + Zero> Zero for NotNan<T> {
|
||||
fn zero() -> Self { NotNan(T::zero()) }
|
||||
|
||||
impl<T: Float + Encodable> Encodable for OrderedFloat<T> {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
self.0.encode(s)
|
||||
}
|
||||
fn is_zero(&self) -> bool { self.0.is_zero() }
|
||||
}
|
||||
|
||||
impl<T: Float + One> One for NotNan<T> {
|
||||
fn one() -> Self { NotNan(T::one()) }
|
||||
}
|
||||
|
||||
impl<T: Float + Bounded> Bounded for NotNan<T> {
|
||||
fn min_value() -> Self {
|
||||
NotNan(Bounded::min_value())
|
||||
}
|
||||
|
||||
impl<T: Float + Decodable> Decodable for OrderedFloat<T> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
|
||||
T::decode(d).map(OrderedFloat)
|
||||
}
|
||||
fn max_value() -> Self {
|
||||
NotNan(Bounded::max_value())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + FromPrimitive> FromPrimitive for NotNan<T> {
|
||||
fn from_i64(n: i64) -> Option<Self> { T::from_i64(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_u64(n: u64) -> Option<Self> { T::from_u64(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
|
||||
fn from_isize(n: isize) -> Option<Self> { T::from_isize(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_i8(n: i8) -> Option<Self> { T::from_i8(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_i16(n: i16) -> Option<Self> { T::from_i16(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_i32(n: i32) -> Option<Self> { T::from_i32(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_usize(n: usize) -> Option<Self> { T::from_usize(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_u8(n: u8) -> Option<Self> { T::from_u8(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_u16(n: u16) -> Option<Self> { T::from_u16(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_u32(n: u32) -> Option<Self> { T::from_u32(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_f32(n: f32) -> Option<Self> { T::from_f32(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
fn from_f64(n: f64) -> Option<Self> { T::from_f64(n).and_then(|n| NotNan::new(n).ok()) }
|
||||
}
|
||||
|
||||
impl<T: Float + ToPrimitive> ToPrimitive for NotNan<T> {
|
||||
fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
|
||||
fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
|
||||
|
||||
fn to_isize(&self) -> Option<isize> { self.0.to_isize() }
|
||||
fn to_i8(&self) -> Option<i8> { self.0.to_i8() }
|
||||
fn to_i16(&self) -> Option<i16> { self.0.to_i16() }
|
||||
fn to_i32(&self) -> Option<i32> { self.0.to_i32() }
|
||||
fn to_usize(&self) -> Option<usize> { self.0.to_usize() }
|
||||
fn to_u8(&self) -> Option<u8> { self.0.to_u8() }
|
||||
fn to_u16(&self) -> Option<u16> { self.0.to_u16() }
|
||||
fn to_u32(&self) -> Option<u32> { self.0.to_u32() }
|
||||
fn to_f32(&self) -> Option<f32> { self.0.to_f32() }
|
||||
fn to_f64(&self) -> Option<f64> { self.0.to_f64() }
|
||||
}
|
||||
|
||||
/// An error indicating a parse error from a string for `NotNan`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ParseNotNanError<E> {
|
||||
/// A plain parse error from the underlying float type.
|
||||
ParseFloatError(E),
|
||||
/// The parsed float value resulted in a NaN.
|
||||
IsNaN,
|
||||
}
|
||||
|
||||
impl<E: fmt::Debug> Error for ParseNotNanError<E> {
|
||||
fn description(&self) -> &str {
|
||||
return "Error parsing a not-NaN floating point value";
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: fmt::Debug> fmt::Display for ParseNotNanError<E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
<Self as fmt::Debug>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + Num> Num for NotNan<T> {
|
||||
type FromStrRadixErr = ParseNotNanError<T::FromStrRadixErr>;
|
||||
|
||||
fn from_str_radix(src: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
T::from_str_radix(src, radix)
|
||||
.map_err(|err| ParseNotNanError::ParseFloatError(err))
|
||||
.and_then(|n| NotNan::new(n).map_err(|_| ParseNotNanError::IsNaN))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + Signed> Signed for NotNan<T> {
|
||||
fn abs(&self) -> Self { NotNan(self.0.abs()) }
|
||||
|
||||
fn abs_sub(&self, other: &Self) -> Self {
|
||||
NotNan::new(self.0.abs_sub(other.0)).expect("Subtraction resulted in NaN")
|
||||
}
|
||||
|
||||
impl<T: Float + Encodable> Encodable for NotNaN<T> {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
self.0.encode(s)
|
||||
}
|
||||
}
|
||||
fn signum(&self) -> Self { NotNan(self.0.signum()) }
|
||||
fn is_positive(&self) -> bool { self.0.is_positive() }
|
||||
fn is_negative(&self) -> bool { self.0.is_negative() }
|
||||
}
|
||||
|
||||
impl<T: Float + Decodable> Decodable for NotNaN<T> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
|
||||
T::decode(d).and_then(|v| NotNaN::new(v).map_err(|e| d.error(e.description())))
|
||||
}
|
||||
impl<T: Float + NumCast> NumCast for NotNan<T> {
|
||||
fn from<F: ToPrimitive>(n: F) -> Option<Self> {
|
||||
T::from(n).and_then(|n| NotNan::new(n).ok())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,34 +683,59 @@ mod impl_rustc {
|
|||
mod impl_serde {
|
||||
extern crate serde;
|
||||
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
use self::serde::de::Error;
|
||||
use super::{OrderedFloat, NotNaN};
|
||||
use self::serde::de::{Error, Unexpected};
|
||||
use super::{OrderedFloat, NotNan};
|
||||
use num_traits::Float;
|
||||
use std::f64;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate serde_test;
|
||||
#[cfg(test)]
|
||||
use self::serde_test::{Token, assert_tokens, assert_de_tokens_error};
|
||||
|
||||
impl<T: Float + Serialize> Serialize for OrderedFloat<T> {
|
||||
fn serialize<S: Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
self.0.serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + Deserialize> Deserialize for OrderedFloat<T> {
|
||||
fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
|
||||
impl<'de, T: Float + Deserialize<'de>> Deserialize<'de> for OrderedFloat<T> {
|
||||
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
T::deserialize(d).map(OrderedFloat)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + Serialize> Serialize for NotNaN<T> {
|
||||
fn serialize<S: Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
impl<T: Float + Serialize> Serialize for NotNan<T> {
|
||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
self.0.serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + Deserialize> Deserialize for NotNaN<T> {
|
||||
fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
|
||||
T::deserialize(d).and_then(|v| {
|
||||
NotNaN::new(v)
|
||||
.map_err(|_| <D::Error as Error>::invalid_value("value cannot be NaN"))
|
||||
impl<'de, T: Float + Deserialize<'de>> Deserialize<'de> for NotNan<T> {
|
||||
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
let float = T::deserialize(d)?;
|
||||
NotNan::new(float).map_err(|_| {
|
||||
Error::invalid_value(Unexpected::Float(f64::NAN), &"float (but not NaN)")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ordered_float() {
|
||||
let float = OrderedFloat(1.0f64);
|
||||
assert_tokens(&float, &[Token::F64(1.0)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_nan() {
|
||||
let float = NotNan(1.0f64);
|
||||
assert_tokens(&float, &[Token::F64(1.0)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fail_on_nan() {
|
||||
assert_de_tokens_error::<NotNan<f64>>(
|
||||
&[Token::F64(f64::NAN)],
|
||||
"invalid value: floating point `NaN`, expected float (but not NaN)");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,524 @@
|
|||
extern crate num_traits;
|
||||
extern crate ordered_float;
|
||||
|
||||
pub use ordered_float::*;
|
||||
pub use num_traits::{Bounded, Float, FromPrimitive, Num, One, Signed, ToPrimitive, Zero};
|
||||
pub use std::cmp::Ordering::*;
|
||||
pub use std::{f32, f64, panic};
|
||||
|
||||
pub use std::collections::hash_map::RandomState;
|
||||
pub use std::collections::HashSet;
|
||||
pub use std::hash::*;
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_regular_floats() {
|
||||
assert_eq!(OrderedFloat(7.0f32).cmp(&OrderedFloat(7.0)), Equal);
|
||||
assert_eq!(OrderedFloat(8.0f32).cmp(&OrderedFloat(7.0)), Greater);
|
||||
assert_eq!(OrderedFloat(4.0f32).cmp(&OrderedFloat(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_regular_floats_op() {
|
||||
assert!(OrderedFloat(7.0f32) == OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0f32) <= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0f32) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0f32) > OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0f32) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0f32) < OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0f32) <= OrderedFloat(7.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_nan() {
|
||||
let f32_nan: f32 = Float::nan();
|
||||
assert_eq!(OrderedFloat(f32_nan).cmp(&OrderedFloat(Float::nan())), Equal);
|
||||
assert_eq!(OrderedFloat(f32_nan).cmp(&OrderedFloat(-100000.0f32)), Greater);
|
||||
assert_eq!(OrderedFloat(-100.0f32).cmp(&OrderedFloat(Float::nan())), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_nan_op() {
|
||||
let f32_nan: OrderedFloat<f32> = OrderedFloat(Float::nan());
|
||||
assert!(f32_nan == f32_nan);
|
||||
assert!(f32_nan <= f32_nan);
|
||||
assert!(f32_nan >= f32_nan);
|
||||
assert!(f32_nan > OrderedFloat(-100000.0f32));
|
||||
assert!(f32_nan >= OrderedFloat(-100000.0f32));
|
||||
assert!(OrderedFloat(-100.0f32) < f32_nan);
|
||||
assert!(OrderedFloat(-100.0f32) <= f32_nan);
|
||||
assert!(f32_nan > OrderedFloat(Float::infinity()));
|
||||
assert!(f32_nan >= OrderedFloat(Float::infinity()));
|
||||
assert!(f32_nan > OrderedFloat(Float::neg_infinity()));
|
||||
assert!(f32_nan >= OrderedFloat(Float::neg_infinity()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_regular_floats() {
|
||||
assert_eq!(OrderedFloat(7.0f64).cmp(&OrderedFloat(7.0)), Equal);
|
||||
assert_eq!(OrderedFloat(8.0f64).cmp(&OrderedFloat(7.0)), Greater);
|
||||
assert_eq!(OrderedFloat(4.0f64).cmp(&OrderedFloat(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_zero() {
|
||||
assert_eq!(NotNan::<f32>::zero(), NotNan::from(0.0f32));
|
||||
assert!(NotNan::<f32>::zero().is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_one() {
|
||||
assert_eq!(NotNan::<f32>::one(), NotNan::from(1.0f32))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_bounded() {
|
||||
assert_eq!(NotNan::<f32>::min_value(), NotNan::from(<f32 as Bounded>::min_value()));
|
||||
assert_eq!(NotNan::<f32>::max_value(), NotNan::from(<f32 as Bounded>::max_value()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_from_primitive() {
|
||||
assert_eq!(NotNan::<f32>::from_i8(42i8), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_u8(42u8), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_i16(42i16), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_u16(42u16), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_i32(42i32), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_u32(42u32), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_i64(42i64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_u64(42u64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_isize(42isize), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_usize(42usize), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_f32(42f32), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_f32(42f32), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_f64(42f64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_f64(42f64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f32>::from_f32(Float::nan()), None);
|
||||
assert_eq!(NotNan::<f32>::from_f64(Float::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_to_primitive() {
|
||||
let x = NotNan::from(42.0f32);
|
||||
assert_eq!(x.to_u8(), Some(42u8));
|
||||
assert_eq!(x.to_i8(), Some(42i8));
|
||||
assert_eq!(x.to_u16(), Some(42u16));
|
||||
assert_eq!(x.to_i16(), Some(42i16));
|
||||
assert_eq!(x.to_u32(), Some(42u32));
|
||||
assert_eq!(x.to_i32(), Some(42i32));
|
||||
assert_eq!(x.to_u64(), Some(42u64));
|
||||
assert_eq!(x.to_i64(), Some(42i64));
|
||||
assert_eq!(x.to_usize(), Some(42usize));
|
||||
assert_eq!(x.to_isize(), Some(42isize));
|
||||
assert_eq!(x.to_f32(), Some(42f32));
|
||||
assert_eq!(x.to_f32(), Some(42f32));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_num() {
|
||||
assert_eq!(NotNan::<f32>::from_str_radix("42.0", 10).unwrap(), NotNan::from(42.0f32));
|
||||
assert!(NotNan::<f32>::from_str_radix("NaN", 10).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_signed() {
|
||||
assert_eq!(NotNan::from(42f32).abs(), NotNan::from(42f32));
|
||||
assert_eq!(NotNan::from(-42f32).abs(), NotNan::from(42f32));
|
||||
|
||||
assert_eq!(NotNan::from(50f32).abs_sub(&NotNan::from(8f32)), NotNan::from(42f32));
|
||||
assert_eq!(NotNan::from(8f32).abs_sub(&NotNan::from(50f32)), NotNan::from(0f32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_num_cast() {
|
||||
assert_eq!(<NotNan<f32> as num_traits::NumCast>::from(42), Some(NotNan::from(42f32)));
|
||||
assert_eq!(<NotNan<f32> as num_traits::NumCast>::from(f32::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_nan() {
|
||||
let f64_nan: f64 = Float::nan();
|
||||
assert_eq!(
|
||||
OrderedFloat(f64_nan).cmp(&OrderedFloat(Float::nan())),
|
||||
Equal
|
||||
);
|
||||
assert_eq!(
|
||||
OrderedFloat(f64_nan).cmp(&OrderedFloat(-100000.0f64)),
|
||||
Greater
|
||||
);
|
||||
assert_eq!(
|
||||
OrderedFloat(-100.0f64).cmp(&OrderedFloat(Float::nan())),
|
||||
Less
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_regular_floats_op() {
|
||||
assert!(OrderedFloat(7.0) == OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0) <= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0) > OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0) < OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0) <= OrderedFloat(7.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_nan_op() {
|
||||
let f64_nan: OrderedFloat<f64> = OrderedFloat(Float::nan());
|
||||
assert!(f64_nan == f64_nan);
|
||||
assert!(f64_nan <= f64_nan);
|
||||
assert!(f64_nan >= f64_nan);
|
||||
assert!(f64_nan > OrderedFloat(-100000.0));
|
||||
assert!(f64_nan >= OrderedFloat(-100000.0));
|
||||
assert!(OrderedFloat(-100.0) < f64_nan);
|
||||
assert!(OrderedFloat(-100.0) <= f64_nan);
|
||||
assert!(f64_nan > OrderedFloat(Float::infinity()));
|
||||
assert!(f64_nan >= OrderedFloat(Float::infinity()));
|
||||
assert!(f64_nan > OrderedFloat(Float::neg_infinity()));
|
||||
assert!(f64_nan >= OrderedFloat(Float::neg_infinity()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_compare_regular_floats() {
|
||||
assert_eq!(NotNan::from(7.0f32).cmp(&NotNan::from(7.0)), Equal);
|
||||
assert_eq!(NotNan::from(8.0f32).cmp(&NotNan::from(7.0)), Greater);
|
||||
assert_eq!(NotNan::from(4.0f32).cmp(&NotNan::from(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_fail_when_constructing_with_nan() {
|
||||
let f32_nan: f32 = Float::nan();
|
||||
assert!(NotNan::new(f32_nan).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_calculate_correctly() {
|
||||
assert_eq!(
|
||||
*(NotNan::from(5.0f32) + NotNan::from(4.0f32)),
|
||||
5.0f32 + 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNan::from(5.0f32) + 4.0f32), 5.0f32 + 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNan::from(5.0f32) - NotNan::from(4.0f32)),
|
||||
5.0f32 - 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNan::from(5.0f32) - 4.0f32), 5.0f32 - 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNan::from(5.0f32) * NotNan::from(4.0f32)),
|
||||
5.0f32 * 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNan::from(5.0f32) * 4.0f32), 5.0f32 * 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNan::from(8.0f32) / NotNan::from(4.0f32)),
|
||||
8.0f32 / 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNan::from(8.0f32) / 4.0f32), 8.0f32 / 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNan::from(8.0f32) % NotNan::from(4.0f32)),
|
||||
8.0f32 % 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNan::from(8.0f32) % 4.0f32), 8.0f32 % 4.0f32);
|
||||
assert_eq!(*(-NotNan::from(1.0f32)), -1.0f32);
|
||||
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f32) + f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f32) - f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f32) * f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f32) / f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f32) % f32::NAN).is_err());
|
||||
|
||||
let mut number = NotNan::from(5.0f32);
|
||||
number += NotNan::from(4.0f32);
|
||||
assert_eq!(*number, 9.0f32);
|
||||
number -= NotNan::from(4.0f32);
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number *= NotNan::from(4.0f32);
|
||||
assert_eq!(*number, 20.0f32);
|
||||
number /= NotNan::from(4.0f32);
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number %= NotNan::from(4.0f32);
|
||||
assert_eq!(*number, 1.0f32);
|
||||
|
||||
number = NotNan::from(5.0f32);
|
||||
number += 4.0f32;
|
||||
assert_eq!(*number, 9.0f32);
|
||||
number -= 4.0f32;
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number *= 4.0f32;
|
||||
assert_eq!(*number, 20.0f32);
|
||||
number /= 4.0f32;
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number %= 4.0f32;
|
||||
assert_eq!(*number, 1.0f32);
|
||||
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f32);
|
||||
tmp += f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f32);
|
||||
tmp -= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f32);
|
||||
tmp *= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f32);
|
||||
tmp /= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f32);
|
||||
tmp %= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_compare_regular_floats() {
|
||||
assert_eq!(NotNan::from(7.0f64).cmp(&NotNan::from(7.0)), Equal);
|
||||
assert_eq!(NotNan::from(8.0f64).cmp(&NotNan::from(7.0)), Greater);
|
||||
assert_eq!(NotNan::from(4.0f64).cmp(&NotNan::from(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_fail_when_constructing_with_nan() {
|
||||
let f64_nan: f64 = Float::nan();
|
||||
assert!(NotNan::new(f64_nan).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_calculate_correctly() {
|
||||
assert_eq!(
|
||||
*(NotNan::from(5.0f64) + NotNan::from(4.0f64)),
|
||||
5.0f64 + 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNan::from(5.0f64) + 4.0f64), 5.0f64 + 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNan::from(5.0f64) - NotNan::from(4.0f64)),
|
||||
5.0f64 - 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNan::from(5.0f64) - 4.0f64), 5.0f64 - 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNan::from(5.0f64) * NotNan::from(4.0f64)),
|
||||
5.0f64 * 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNan::from(5.0f64) * 4.0f64), 5.0f64 * 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNan::from(8.0f64) / NotNan::from(4.0f64)),
|
||||
8.0f64 / 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNan::from(8.0f64) / 4.0f64), 8.0f64 / 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNan::from(8.0f64) % NotNan::from(4.0f64)),
|
||||
8.0f64 % 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNan::from(8.0f64) % 4.0f64), 8.0f64 % 4.0f64);
|
||||
assert_eq!(*(-NotNan::from(1.0f64)), -1.0f64);
|
||||
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f64) + f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f64) - f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f64) * f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f64) / f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNan::from(0.0f64) % f64::NAN).is_err());
|
||||
|
||||
let mut number = NotNan::from(5.0f64);
|
||||
number += NotNan::from(4.0f64);
|
||||
assert_eq!(*number, 9.0f64);
|
||||
number -= NotNan::from(4.0f64);
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number *= NotNan::from(4.0f64);
|
||||
assert_eq!(*number, 20.0f64);
|
||||
number /= NotNan::from(4.0f64);
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number %= NotNan::from(4.0f64);
|
||||
assert_eq!(*number, 1.0f64);
|
||||
|
||||
number = NotNan::from(5.0f64);
|
||||
number += 4.0f64;
|
||||
assert_eq!(*number, 9.0f64);
|
||||
number -= 4.0f64;
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number *= 4.0f64;
|
||||
assert_eq!(*number, 20.0f64);
|
||||
number /= 4.0f64;
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number %= 4.0f64;
|
||||
assert_eq!(*number, 1.0f64);
|
||||
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f64);
|
||||
tmp += f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f64);
|
||||
tmp -= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f64);
|
||||
tmp *= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f64);
|
||||
tmp /= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNan::from(0.0f64);
|
||||
tmp %= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_zero() {
|
||||
assert_eq!(NotNan::<f64>::zero(), NotNan::from(0.0f64));
|
||||
assert!(NotNan::<f64>::zero().is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_one() {
|
||||
assert_eq!(NotNan::<f64>::one(), NotNan::from(1.0f64))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_bounded() {
|
||||
assert_eq!(NotNan::<f64>::min_value(), NotNan::from(<f64 as Bounded>::min_value()));
|
||||
assert_eq!(NotNan::<f64>::max_value(), NotNan::from(<f64 as Bounded>::max_value()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_from_primitive() {
|
||||
assert_eq!(NotNan::<f64>::from_i8(42i8), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_u8(42u8), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_i16(42i16), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_u16(42u16), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_i32(42i32), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_u32(42u32), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_i64(42i64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_u64(42u64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_isize(42isize), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_usize(42usize), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_f64(42f64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_f64(42f64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_f64(42f64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_f64(42f64), Some(NotNan::from(42.0)));
|
||||
assert_eq!(NotNan::<f64>::from_f64(Float::nan()), None);
|
||||
assert_eq!(NotNan::<f64>::from_f64(Float::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_to_primitive() {
|
||||
let x = NotNan::from(42.0f64);
|
||||
assert_eq!(x.to_u8(), Some(42u8));
|
||||
assert_eq!(x.to_i8(), Some(42i8));
|
||||
assert_eq!(x.to_u16(), Some(42u16));
|
||||
assert_eq!(x.to_i16(), Some(42i16));
|
||||
assert_eq!(x.to_u32(), Some(42u32));
|
||||
assert_eq!(x.to_i32(), Some(42i32));
|
||||
assert_eq!(x.to_u64(), Some(42u64));
|
||||
assert_eq!(x.to_i64(), Some(42i64));
|
||||
assert_eq!(x.to_usize(), Some(42usize));
|
||||
assert_eq!(x.to_isize(), Some(42isize));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_num() {
|
||||
assert_eq!(NotNan::<f64>::from_str_radix("42.0", 10).unwrap(), NotNan::from(42.0f64));
|
||||
assert!(NotNan::<f64>::from_str_radix("NaN", 10).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_signed() {
|
||||
assert_eq!(NotNan::from(42f64).abs(), NotNan::from(42f64));
|
||||
assert_eq!(NotNan::from(-42f64).abs(), NotNan::from(42f64));
|
||||
|
||||
assert_eq!(NotNan::from(50f64).abs_sub(&NotNan::from(8f64)), NotNan::from(42f64));
|
||||
assert_eq!(NotNan::from(8f64).abs_sub(&NotNan::from(50f64)), NotNan::from(0f64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_num_cast() {
|
||||
assert_eq!(<NotNan<f64> as num_traits::NumCast>::from(42), Some(NotNan::from(42f64)));
|
||||
assert_eq!(<NotNan<f64> as num_traits::NumCast>::from(f64::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_zero_and_neg_zero_to_the_same_hc() {
|
||||
let state = RandomState::new();
|
||||
let mut h1 = state.build_hasher();
|
||||
let mut h2 = state.build_hasher();
|
||||
OrderedFloat::from(0f64).hash(&mut h1);
|
||||
OrderedFloat::from(-0f64).hash(&mut h2);
|
||||
assert_eq!(h1.finish(), h2.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_inf_and_neg_inf_to_different_hcs() {
|
||||
let state = RandomState::new();
|
||||
let mut h1 = state.build_hasher();
|
||||
let mut h2 = state.build_hasher();
|
||||
OrderedFloat::from(f64::INFINITY).hash(&mut h1);
|
||||
OrderedFloat::from(f64::NEG_INFINITY).hash(&mut h2);
|
||||
assert!(h1.finish() != h2.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_is_good_for_whole_numbers() {
|
||||
let state = RandomState::new();
|
||||
let limit = 10000;
|
||||
|
||||
let mut set = ::std::collections::HashSet::with_capacity(limit);
|
||||
for i in 0..limit {
|
||||
let mut h = state.build_hasher();
|
||||
OrderedFloat::from(i as f64).hash(&mut h);
|
||||
set.insert(h.finish());
|
||||
}
|
||||
|
||||
// This allows 100 collisions, which is far too
|
||||
// many, but should guard against transient issues
|
||||
// that will result from using RandomState
|
||||
let pct_unique = set.len() as f64 / limit as f64;
|
||||
assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_is_good_for_fractional_numbers() {
|
||||
let state = RandomState::new();
|
||||
let limit = 10000;
|
||||
|
||||
let mut set = ::std::collections::HashSet::with_capacity(limit);
|
||||
for i in 0..limit {
|
||||
let mut h = state.build_hasher();
|
||||
OrderedFloat::from(i as f64 * (1f64 / limit as f64)).hash(&mut h);
|
||||
set.insert(h.finish());
|
||||
}
|
||||
|
||||
// This allows 100 collisions, which is far too
|
||||
// many, but should guard against transient issues
|
||||
// that will result from using RandomState
|
||||
let pct_unique = set.len() as f64 / limit as f64;
|
||||
assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique);
|
||||
}
|
|
@ -0,0 +1,526 @@
|
|||
#![allow(deprecated)]
|
||||
|
||||
extern crate num_traits;
|
||||
extern crate ordered_float;
|
||||
|
||||
pub use ordered_float::*;
|
||||
pub use num_traits::{Bounded, Float, FromPrimitive, Num, One, Signed, ToPrimitive, Zero};
|
||||
pub use std::cmp::Ordering::*;
|
||||
pub use std::{f32, f64, panic};
|
||||
|
||||
pub use std::collections::hash_map::RandomState;
|
||||
pub use std::collections::HashSet;
|
||||
pub use std::hash::*;
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_regular_floats() {
|
||||
assert_eq!(OrderedFloat(7.0f32).cmp(&OrderedFloat(7.0)), Equal);
|
||||
assert_eq!(OrderedFloat(8.0f32).cmp(&OrderedFloat(7.0)), Greater);
|
||||
assert_eq!(OrderedFloat(4.0f32).cmp(&OrderedFloat(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_regular_floats_op() {
|
||||
assert!(OrderedFloat(7.0f32) == OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0f32) <= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0f32) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0f32) > OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0f32) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0f32) < OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0f32) <= OrderedFloat(7.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_nan() {
|
||||
let f32_nan: f32 = Float::nan();
|
||||
assert_eq!(OrderedFloat(f32_nan).cmp(&OrderedFloat(Float::nan())), Equal);
|
||||
assert_eq!(OrderedFloat(f32_nan).cmp(&OrderedFloat(-100000.0f32)), Greater);
|
||||
assert_eq!(OrderedFloat(-100.0f32).cmp(&OrderedFloat(Float::nan())), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f32_compare_nan_op() {
|
||||
let f32_nan: OrderedFloat<f32> = OrderedFloat(Float::nan());
|
||||
assert!(f32_nan == f32_nan);
|
||||
assert!(f32_nan <= f32_nan);
|
||||
assert!(f32_nan >= f32_nan);
|
||||
assert!(f32_nan > OrderedFloat(-100000.0f32));
|
||||
assert!(f32_nan >= OrderedFloat(-100000.0f32));
|
||||
assert!(OrderedFloat(-100.0f32) < f32_nan);
|
||||
assert!(OrderedFloat(-100.0f32) <= f32_nan);
|
||||
assert!(f32_nan > OrderedFloat(Float::infinity()));
|
||||
assert!(f32_nan >= OrderedFloat(Float::infinity()));
|
||||
assert!(f32_nan > OrderedFloat(Float::neg_infinity()));
|
||||
assert!(f32_nan >= OrderedFloat(Float::neg_infinity()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_regular_floats() {
|
||||
assert_eq!(OrderedFloat(7.0f64).cmp(&OrderedFloat(7.0)), Equal);
|
||||
assert_eq!(OrderedFloat(8.0f64).cmp(&OrderedFloat(7.0)), Greater);
|
||||
assert_eq!(OrderedFloat(4.0f64).cmp(&OrderedFloat(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_zero() {
|
||||
assert_eq!(NotNaN::<f32>::zero(), NotNaN::from(0.0f32));
|
||||
assert!(NotNaN::<f32>::zero().is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_one() {
|
||||
assert_eq!(NotNaN::<f32>::one(), NotNaN::from(1.0f32))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_bounded() {
|
||||
assert_eq!(NotNaN::<f32>::min_value(), NotNaN::from(<f32 as Bounded>::min_value()));
|
||||
assert_eq!(NotNaN::<f32>::max_value(), NotNaN::from(<f32 as Bounded>::max_value()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_from_primitive() {
|
||||
assert_eq!(NotNaN::<f32>::from_i8(42i8), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_u8(42u8), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_i16(42i16), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_u16(42u16), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_i32(42i32), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_u32(42u32), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_i64(42i64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_u64(42u64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_isize(42isize), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_usize(42usize), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_f32(42f32), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_f32(42f32), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_f64(42f64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_f64(42f64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f32>::from_f32(Float::nan()), None);
|
||||
assert_eq!(NotNaN::<f32>::from_f64(Float::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_to_primitive() {
|
||||
let x = NotNaN::from(42.0f32);
|
||||
assert_eq!(x.to_u8(), Some(42u8));
|
||||
assert_eq!(x.to_i8(), Some(42i8));
|
||||
assert_eq!(x.to_u16(), Some(42u16));
|
||||
assert_eq!(x.to_i16(), Some(42i16));
|
||||
assert_eq!(x.to_u32(), Some(42u32));
|
||||
assert_eq!(x.to_i32(), Some(42i32));
|
||||
assert_eq!(x.to_u64(), Some(42u64));
|
||||
assert_eq!(x.to_i64(), Some(42i64));
|
||||
assert_eq!(x.to_usize(), Some(42usize));
|
||||
assert_eq!(x.to_isize(), Some(42isize));
|
||||
assert_eq!(x.to_f32(), Some(42f32));
|
||||
assert_eq!(x.to_f32(), Some(42f32));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_num() {
|
||||
assert_eq!(NotNaN::<f32>::from_str_radix("42.0", 10).unwrap(), NotNaN::from(42.0f32));
|
||||
assert!(NotNaN::<f32>::from_str_radix("NaN", 10).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_signed() {
|
||||
assert_eq!(NotNaN::from(42f32).abs(), NotNaN::from(42f32));
|
||||
assert_eq!(NotNaN::from(-42f32).abs(), NotNaN::from(42f32));
|
||||
|
||||
assert_eq!(NotNaN::from(50f32).abs_sub(&NotNaN::from(8f32)), NotNaN::from(42f32));
|
||||
assert_eq!(NotNaN::from(8f32).abs_sub(&NotNaN::from(50f32)), NotNaN::from(0f32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_num_cast() {
|
||||
assert_eq!(<NotNaN<f32> as num_traits::NumCast>::from(42), Some(NotNaN::from(42f32)));
|
||||
assert_eq!(<NotNaN<f32> as num_traits::NumCast>::from(f32::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_nan() {
|
||||
let f64_nan: f64 = Float::nan();
|
||||
assert_eq!(
|
||||
OrderedFloat(f64_nan).cmp(&OrderedFloat(Float::nan())),
|
||||
Equal
|
||||
);
|
||||
assert_eq!(
|
||||
OrderedFloat(f64_nan).cmp(&OrderedFloat(-100000.0f64)),
|
||||
Greater
|
||||
);
|
||||
assert_eq!(
|
||||
OrderedFloat(-100.0f64).cmp(&OrderedFloat(Float::nan())),
|
||||
Less
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_regular_floats_op() {
|
||||
assert!(OrderedFloat(7.0) == OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0) <= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(7.0) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0) > OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(8.0) >= OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0) < OrderedFloat(7.0));
|
||||
assert!(OrderedFloat(4.0) <= OrderedFloat(7.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordered_f64_compare_nan_op() {
|
||||
let f64_nan: OrderedFloat<f64> = OrderedFloat(Float::nan());
|
||||
assert!(f64_nan == f64_nan);
|
||||
assert!(f64_nan <= f64_nan);
|
||||
assert!(f64_nan >= f64_nan);
|
||||
assert!(f64_nan > OrderedFloat(-100000.0));
|
||||
assert!(f64_nan >= OrderedFloat(-100000.0));
|
||||
assert!(OrderedFloat(-100.0) < f64_nan);
|
||||
assert!(OrderedFloat(-100.0) <= f64_nan);
|
||||
assert!(f64_nan > OrderedFloat(Float::infinity()));
|
||||
assert!(f64_nan >= OrderedFloat(Float::infinity()));
|
||||
assert!(f64_nan > OrderedFloat(Float::neg_infinity()));
|
||||
assert!(f64_nan >= OrderedFloat(Float::neg_infinity()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_compare_regular_floats() {
|
||||
assert_eq!(NotNaN::from(7.0f32).cmp(&NotNaN::from(7.0)), Equal);
|
||||
assert_eq!(NotNaN::from(8.0f32).cmp(&NotNaN::from(7.0)), Greater);
|
||||
assert_eq!(NotNaN::from(4.0f32).cmp(&NotNaN::from(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_fail_when_constructing_with_nan() {
|
||||
let f32_nan: f32 = Float::nan();
|
||||
assert!(NotNaN::new(f32_nan).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan32_calculate_correctly() {
|
||||
assert_eq!(
|
||||
*(NotNaN::from(5.0f32) + NotNaN::from(4.0f32)),
|
||||
5.0f32 + 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) + 4.0f32), 5.0f32 + 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(5.0f32) - NotNaN::from(4.0f32)),
|
||||
5.0f32 - 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) - 4.0f32), 5.0f32 - 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(5.0f32) * NotNaN::from(4.0f32)),
|
||||
5.0f32 * 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) * 4.0f32), 5.0f32 * 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(8.0f32) / NotNaN::from(4.0f32)),
|
||||
8.0f32 / 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(8.0f32) / 4.0f32), 8.0f32 / 4.0f32);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(8.0f32) % NotNaN::from(4.0f32)),
|
||||
8.0f32 % 4.0f32
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(8.0f32) % 4.0f32), 8.0f32 % 4.0f32);
|
||||
assert_eq!(*(-NotNaN::from(1.0f32)), -1.0f32);
|
||||
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f32) + f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f32) - f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f32) * f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f32) / f32::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f32) % f32::NAN).is_err());
|
||||
|
||||
let mut number = NotNaN::from(5.0f32);
|
||||
number += NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 9.0f32);
|
||||
number -= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number *= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 20.0f32);
|
||||
number /= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number %= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 1.0f32);
|
||||
|
||||
number = NotNaN::from(5.0f32);
|
||||
number += 4.0f32;
|
||||
assert_eq!(*number, 9.0f32);
|
||||
number -= 4.0f32;
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number *= 4.0f32;
|
||||
assert_eq!(*number, 20.0f32);
|
||||
number /= 4.0f32;
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number %= 4.0f32;
|
||||
assert_eq!(*number, 1.0f32);
|
||||
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f32);
|
||||
tmp += f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f32);
|
||||
tmp -= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f32);
|
||||
tmp *= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f32);
|
||||
tmp /= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f32);
|
||||
tmp %= f32::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_compare_regular_floats() {
|
||||
assert_eq!(NotNaN::from(7.0f64).cmp(&NotNaN::from(7.0)), Equal);
|
||||
assert_eq!(NotNaN::from(8.0f64).cmp(&NotNaN::from(7.0)), Greater);
|
||||
assert_eq!(NotNaN::from(4.0f64).cmp(&NotNaN::from(7.0)), Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_fail_when_constructing_with_nan() {
|
||||
let f64_nan: f64 = Float::nan();
|
||||
assert!(NotNaN::new(f64_nan).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_calculate_correctly() {
|
||||
assert_eq!(
|
||||
*(NotNaN::from(5.0f64) + NotNaN::from(4.0f64)),
|
||||
5.0f64 + 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) + 4.0f64), 5.0f64 + 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(5.0f64) - NotNaN::from(4.0f64)),
|
||||
5.0f64 - 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) - 4.0f64), 5.0f64 - 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(5.0f64) * NotNaN::from(4.0f64)),
|
||||
5.0f64 * 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) * 4.0f64), 5.0f64 * 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(8.0f64) / NotNaN::from(4.0f64)),
|
||||
8.0f64 / 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(8.0f64) / 4.0f64), 8.0f64 / 4.0f64);
|
||||
assert_eq!(
|
||||
*(NotNaN::from(8.0f64) % NotNaN::from(4.0f64)),
|
||||
8.0f64 % 4.0f64
|
||||
);
|
||||
assert_eq!(*(NotNaN::from(8.0f64) % 4.0f64), 8.0f64 % 4.0f64);
|
||||
assert_eq!(*(-NotNaN::from(1.0f64)), -1.0f64);
|
||||
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f64) + f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f64) - f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f64) * f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f64) / f64::NAN).is_err());
|
||||
assert!(panic::catch_unwind(|| NotNaN::from(0.0f64) % f64::NAN).is_err());
|
||||
|
||||
let mut number = NotNaN::from(5.0f64);
|
||||
number += NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 9.0f64);
|
||||
number -= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number *= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 20.0f64);
|
||||
number /= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number %= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 1.0f64);
|
||||
|
||||
number = NotNaN::from(5.0f64);
|
||||
number += 4.0f64;
|
||||
assert_eq!(*number, 9.0f64);
|
||||
number -= 4.0f64;
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number *= 4.0f64;
|
||||
assert_eq!(*number, 20.0f64);
|
||||
number /= 4.0f64;
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number %= 4.0f64;
|
||||
assert_eq!(*number, 1.0f64);
|
||||
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f64);
|
||||
tmp += f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f64);
|
||||
tmp -= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f64);
|
||||
tmp *= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f64);
|
||||
tmp /= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
assert!(
|
||||
panic::catch_unwind(|| {
|
||||
let mut tmp = NotNaN::from(0.0f64);
|
||||
tmp %= f64::NAN;
|
||||
}).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_zero() {
|
||||
assert_eq!(NotNaN::<f64>::zero(), NotNaN::from(0.0f64));
|
||||
assert!(NotNaN::<f64>::zero().is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_one() {
|
||||
assert_eq!(NotNaN::<f64>::one(), NotNaN::from(1.0f64))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_bounded() {
|
||||
assert_eq!(NotNaN::<f64>::min_value(), NotNaN::from(<f64 as Bounded>::min_value()));
|
||||
assert_eq!(NotNaN::<f64>::max_value(), NotNaN::from(<f64 as Bounded>::max_value()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_from_primitive() {
|
||||
assert_eq!(NotNaN::<f64>::from_i8(42i8), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_u8(42u8), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_i16(42i16), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_u16(42u16), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_i32(42i32), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_u32(42u32), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_i64(42i64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_u64(42u64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_isize(42isize), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_usize(42usize), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_f64(42f64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_f64(42f64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_f64(42f64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_f64(42f64), Some(NotNaN::from(42.0)));
|
||||
assert_eq!(NotNaN::<f64>::from_f64(Float::nan()), None);
|
||||
assert_eq!(NotNaN::<f64>::from_f64(Float::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_to_primitive() {
|
||||
let x = NotNaN::from(42.0f64);
|
||||
assert_eq!(x.to_u8(), Some(42u8));
|
||||
assert_eq!(x.to_i8(), Some(42i8));
|
||||
assert_eq!(x.to_u16(), Some(42u16));
|
||||
assert_eq!(x.to_i16(), Some(42i16));
|
||||
assert_eq!(x.to_u32(), Some(42u32));
|
||||
assert_eq!(x.to_i32(), Some(42i32));
|
||||
assert_eq!(x.to_u64(), Some(42u64));
|
||||
assert_eq!(x.to_i64(), Some(42i64));
|
||||
assert_eq!(x.to_usize(), Some(42usize));
|
||||
assert_eq!(x.to_isize(), Some(42isize));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
assert_eq!(x.to_f64(), Some(42f64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_num() {
|
||||
assert_eq!(NotNaN::<f64>::from_str_radix("42.0", 10).unwrap(), NotNaN::from(42.0f64));
|
||||
assert!(NotNaN::<f64>::from_str_radix("NaN", 10).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_signed() {
|
||||
assert_eq!(NotNaN::from(42f64).abs(), NotNaN::from(42f64));
|
||||
assert_eq!(NotNaN::from(-42f64).abs(), NotNaN::from(42f64));
|
||||
|
||||
assert_eq!(NotNaN::from(50f64).abs_sub(&NotNaN::from(8f64)), NotNaN::from(42f64));
|
||||
assert_eq!(NotNaN::from(8f64).abs_sub(&NotNaN::from(50f64)), NotNaN::from(0f64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_nan64_num_cast() {
|
||||
assert_eq!(<NotNaN<f64> as num_traits::NumCast>::from(42), Some(NotNaN::from(42f64)));
|
||||
assert_eq!(<NotNaN<f64> as num_traits::NumCast>::from(f64::nan()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_zero_and_neg_zero_to_the_same_hc() {
|
||||
let state = RandomState::new();
|
||||
let mut h1 = state.build_hasher();
|
||||
let mut h2 = state.build_hasher();
|
||||
OrderedFloat::from(0f64).hash(&mut h1);
|
||||
OrderedFloat::from(-0f64).hash(&mut h2);
|
||||
assert_eq!(h1.finish(), h2.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_inf_and_neg_inf_to_different_hcs() {
|
||||
let state = RandomState::new();
|
||||
let mut h1 = state.build_hasher();
|
||||
let mut h2 = state.build_hasher();
|
||||
OrderedFloat::from(f64::INFINITY).hash(&mut h1);
|
||||
OrderedFloat::from(f64::NEG_INFINITY).hash(&mut h2);
|
||||
assert!(h1.finish() != h2.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_is_good_for_whole_numbers() {
|
||||
let state = RandomState::new();
|
||||
let limit = 10000;
|
||||
|
||||
let mut set = ::std::collections::HashSet::with_capacity(limit);
|
||||
for i in 0..limit {
|
||||
let mut h = state.build_hasher();
|
||||
OrderedFloat::from(i as f64).hash(&mut h);
|
||||
set.insert(h.finish());
|
||||
}
|
||||
|
||||
// This allows 100 collisions, which is far too
|
||||
// many, but should guard against transient issues
|
||||
// that will result from using RandomState
|
||||
let pct_unique = set.len() as f64 / limit as f64;
|
||||
assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_is_good_for_fractional_numbers() {
|
||||
let state = RandomState::new();
|
||||
let limit = 10000;
|
||||
|
||||
let mut set = ::std::collections::HashSet::with_capacity(limit);
|
||||
for i in 0..limit {
|
||||
let mut h = state.build_hasher();
|
||||
OrderedFloat::from(i as f64 * (1f64 / limit as f64)).hash(&mut h);
|
||||
set.insert(h.finish());
|
||||
}
|
||||
|
||||
// This allows 100 collisions, which is far too
|
||||
// many, but should guard against transient issues
|
||||
// that will result from using RandomState
|
||||
let pct_unique = set.len() as f64 / limit as f64;
|
||||
assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"files":{".travis.yml":"d91d0d75087934c2d0503a8c04439fea459a19182021bb0b699644d442f5b6fc","Cargo.toml":"4081c443d3318411bec6bf1dd8284b7ef4eb39994ca2be66292f0bce6ffae9f6","LICENSE-MIT":"f7715d38a3fa1b4ac97c5729740752505a39cb92ee83ab5b102aeb5eaa7cdea4","README.md":"36ffe300159d4ce4c8224969723606312770117a0a25fbcb3534922c8248b0e9","examples/simple.rs":"c05b124bdad67bfe9e48998bff6a7c6a8789e7f7c9fb3f318f8028a68ef944ed","src/lib.rs":"08a58847b86729b9b2a4eb1125457fc5e76206f9f86a014c1ba26ce6e3f0ebac","tests/check.rs":"ac8691f78269e1cb0cd010150e707f5ea5df14055883f0ee5a5b55a686c5b8de"},"package":"0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"}
|
|
@ -0,0 +1,27 @@
|
|||
# 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 = "new_debug_unreachable"
|
||||
version = "1.0.1"
|
||||
authors = ["Matt Brubeck <mbrubeck@limpet.net>", "Jonathan Reem <jonathan.reem@gmail.com>"]
|
||||
description = "panic in debug, intrinsics::unreachable() in release (fork of debug_unreachable)"
|
||||
documentation = "https://docs.rs/new_debug_unreachable"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/mbrubeck/rust-debug-unreachable"
|
||||
|
||||
[lib]
|
||||
name = "debug_unreachable"
|
||||
path = "src/lib.rs"
|
||||
[dependencies.unreachable]
|
||||
version = "1.0"
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2015 Jonathan Reem
|
||||
|
||||
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.
|
|
@ -0,0 +1,27 @@
|
|||
# new_debug_unreachable
|
||||
|
||||
> unreachable!() in debug, std::intrinsics::unreachable() in release.
|
||||
|
||||
This is a fork of [`debug_unreachable`](https://crates.io/crates/debug_unreachable).
|
||||
|
||||
## [Documentation](https://docs.rs/new_debug_unreachable)
|
||||
|
||||
## Usage
|
||||
|
||||
Use the crates.io repository; add this to your `Cargo.toml` along
|
||||
with the rest of your dependencies:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
new_debug_unreachable = "1.0"
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
[Jonathan Reem](https://medium.com/@jreem) is the original author of debug-unreachable.
|
||||
|
||||
[Matt Brubeck](https://limpet.net/mbrubeck/) is the maintainer of this fork.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
|
@ -1,5 +1,7 @@
|
|||
#![deny(missing_docs, warnings)]
|
||||
|
||||
#![no_std]
|
||||
|
||||
//! `panic!()` in debug builds, optimization hint in release.
|
||||
|
||||
extern crate unreachable;
|
||||
|
@ -12,10 +14,10 @@ pub use unreachable::unreachable as __unreachable;
|
|||
macro_rules! debug_unreachable {
|
||||
() => { debug_unreachable!("entered unreachable code") };
|
||||
($e:expr) => {
|
||||
if cfg!(ndebug) {
|
||||
$crate::__unreachable()
|
||||
} else {
|
||||
if cfg!(debug_assertions) {
|
||||
panic!($e);
|
||||
} else {
|
||||
$crate::__unreachable()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"836b2a8c7fc40a6b7fafc7ae6d4cc0cfc5e8cd1ce9023843ed471f1d5f41af8b","Cargo.toml":"fa8d70d0447555cbda365af477d0bb43fefa964562d76b262ec67f0f2e658bd4","README.md":"10c54822e3ec242a69f9abcbf15cec555f666280336b0e650d6f008c982adc7c","src/lib.rs":"d0dbfdac8aa6d7be0bf0d4e443a197b88f73262f88670df531c84993aa4bc45c","tests/test.rs":"f339d8b594fb450903349fba93d04d91322a2c947b5d5ebb475ca10ae04a0eb2"},"package":"da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"}
|
|
@ -1,17 +0,0 @@
|
|||
[package]
|
||||
|
||||
name = "ordered-float"
|
||||
version = "0.4.0"
|
||||
authors = ["Jonathan Reem <jonathan.reem@gmail.com>"]
|
||||
license = "MIT"
|
||||
description = "Wrappers for total ordering on floats."
|
||||
repository = "https://github.com/reem/rust-ordered-float"
|
||||
|
||||
[dependencies]
|
||||
num-traits = { version = "0.1", default_features = false }
|
||||
serde = { version = "0.8", optional = true }
|
||||
rustc-serialize = { version = "0.3", optional = true }
|
||||
unreachable = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
stainless = "0.1"
|
|
@ -1,15 +0,0 @@
|
|||
# Ordered Floats
|
||||
|
||||
Provides several wrapper types for Ord and Eq implementations on f64.
|
||||
|
||||
See `src/lib.rs` for documentation and details.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Tools
|
||||
|
||||
Built using Cargo
|
||||
Tested using Stainless
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(stainless)]
|
||||
|
||||
extern crate ordered_float;
|
||||
extern crate num_traits;
|
||||
|
||||
pub use ordered_float::*;
|
||||
pub use num_traits::Float;
|
||||
pub use std::cmp::Ordering::*;
|
||||
pub use std::{f32, f64, panic};
|
||||
|
||||
pub use std::collections::HashSet;
|
||||
pub use std::collections::hash_map::RandomState;
|
||||
pub use std::hash::*;
|
||||
|
||||
describe! ordered_float32 {
|
||||
it "should compare regular floats" {
|
||||
assert_eq!(OrderedFloat(7.0f32).cmp(&OrderedFloat(7.0)), Equal);
|
||||
assert_eq!(OrderedFloat(8.0f32).cmp(&OrderedFloat(7.0)), Greater);
|
||||
assert_eq!(OrderedFloat(4.0f32).cmp(&OrderedFloat(7.0)), Less);
|
||||
}
|
||||
|
||||
it "should compare NaN" {
|
||||
let f32_nan: f32 = Float::nan();
|
||||
assert_eq!(OrderedFloat(f32_nan).cmp(&OrderedFloat(Float::nan())), Equal);
|
||||
assert_eq!(OrderedFloat(f32_nan).cmp(&OrderedFloat(-100000.0f32)), Greater);
|
||||
assert_eq!(OrderedFloat(-100.0f32).cmp(&OrderedFloat(Float::nan())), Less);
|
||||
}
|
||||
}
|
||||
|
||||
describe! ordered_float64 {
|
||||
it "should compare regular floats" {
|
||||
assert_eq!(OrderedFloat(7.0f64).cmp(&OrderedFloat(7.0)), Equal);
|
||||
assert_eq!(OrderedFloat(8.0f64).cmp(&OrderedFloat(7.0)), Greater);
|
||||
assert_eq!(OrderedFloat(4.0f64).cmp(&OrderedFloat(7.0)), Less);
|
||||
}
|
||||
|
||||
it "should compare NaN" {
|
||||
let f64_nan: f64 = Float::nan();
|
||||
assert_eq!(OrderedFloat(f64_nan).cmp(&OrderedFloat(Float::nan())), Equal);
|
||||
assert_eq!(OrderedFloat(f64_nan).cmp(&OrderedFloat(-100000.0f64)), Greater);
|
||||
assert_eq!(OrderedFloat(-100.0f64).cmp(&OrderedFloat(Float::nan())), Less);
|
||||
}
|
||||
}
|
||||
|
||||
describe! not_nan32 {
|
||||
it "should compare regular floats" {
|
||||
assert_eq!(NotNaN::from(7.0f32).cmp(&NotNaN::from(7.0)), Equal);
|
||||
assert_eq!(NotNaN::from(8.0f32).cmp(&NotNaN::from(7.0)), Greater);
|
||||
assert_eq!(NotNaN::from(4.0f32).cmp(&NotNaN::from(7.0)), Less);
|
||||
}
|
||||
|
||||
it "should fail when constructing NotNaN with NaN" {
|
||||
let f32_nan: f32 = Float::nan();
|
||||
assert!(NotNaN::new(f32_nan).is_err());
|
||||
}
|
||||
|
||||
it "should calculate correctly" {
|
||||
assert_eq!(*(NotNaN::from(5.0f32) + NotNaN::from(4.0f32)), 5.0f32 + 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) + 4.0f32), 5.0f32 + 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) - NotNaN::from(4.0f32)), 5.0f32 - 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) - 4.0f32), 5.0f32 - 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) * NotNaN::from(4.0f32)), 5.0f32 * 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(5.0f32) * 4.0f32), 5.0f32 * 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(8.0f32) / NotNaN::from(4.0f32)), 8.0f32 / 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(8.0f32) / 4.0f32), 8.0f32 / 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(8.0f32) % NotNaN::from(4.0f32)), 8.0f32 % 4.0f32);
|
||||
assert_eq!(*(NotNaN::from(8.0f32) % 4.0f32), 8.0f32 % 4.0f32);
|
||||
assert_eq!(*(-NotNaN::from(1.0f32)), -1.0f32);
|
||||
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f32) + f32::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f32) - f32::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f32) * f32::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f32) / f32::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f32) % f32::NAN}).is_err());
|
||||
|
||||
let mut number = NotNaN::from(5.0f32);
|
||||
number += NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 9.0f32);
|
||||
number -= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number *= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 20.0f32);
|
||||
number /= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number %= NotNaN::from(4.0f32);
|
||||
assert_eq!(*number, 1.0f32);
|
||||
|
||||
number = NotNaN::from(5.0f32);
|
||||
number += 4.0f32;
|
||||
assert_eq!(*number, 9.0f32);
|
||||
number -= 4.0f32;
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number *= 4.0f32;
|
||||
assert_eq!(*number, 20.0f32);
|
||||
number /= 4.0f32;
|
||||
assert_eq!(*number, 5.0f32);
|
||||
number %= 4.0f32;
|
||||
assert_eq!(*number, 1.0f32);
|
||||
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f32); tmp += f32::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f32); tmp -= f32::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f32); tmp *= f32::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f32); tmp /= f32::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f32); tmp %= f32::NAN;}).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
describe! not_nan64 {
|
||||
it "should compare regular floats" {
|
||||
assert_eq!(NotNaN::from(7.0f64).cmp(&NotNaN::from(7.0)), Equal);
|
||||
assert_eq!(NotNaN::from(8.0f64).cmp(&NotNaN::from(7.0)), Greater);
|
||||
assert_eq!(NotNaN::from(4.0f64).cmp(&NotNaN::from(7.0)), Less);
|
||||
}
|
||||
|
||||
it "should fail when constructing NotNaN with NaN" {
|
||||
let f64_nan: f64 = Float::nan();
|
||||
assert!(NotNaN::new(f64_nan).is_err());
|
||||
}
|
||||
|
||||
it "should calculate correctly" {
|
||||
assert_eq!(*(NotNaN::from(5.0f64) + NotNaN::from(4.0f64)), 5.0f64 + 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) + 4.0f64), 5.0f64 + 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) - NotNaN::from(4.0f64)), 5.0f64 - 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) - 4.0f64), 5.0f64 - 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) * NotNaN::from(4.0f64)), 5.0f64 * 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(5.0f64) * 4.0f64), 5.0f64 * 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(8.0f64) / NotNaN::from(4.0f64)), 8.0f64 / 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(8.0f64) / 4.0f64), 8.0f64 / 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(8.0f64) % NotNaN::from(4.0f64)), 8.0f64 % 4.0f64);
|
||||
assert_eq!(*(NotNaN::from(8.0f64) % 4.0f64), 8.0f64 % 4.0f64);
|
||||
assert_eq!(*(-NotNaN::from(1.0f64)), -1.0f64);
|
||||
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f64) + f64::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f64) - f64::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f64) * f64::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f64) / f64::NAN}).is_err());
|
||||
assert!(panic::catch_unwind(|| {NotNaN::from(0.0f64) % f64::NAN}).is_err());
|
||||
|
||||
let mut number = NotNaN::from(5.0f64);
|
||||
number += NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 9.0f64);
|
||||
number -= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number *= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 20.0f64);
|
||||
number /= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number %= NotNaN::from(4.0f64);
|
||||
assert_eq!(*number, 1.0f64);
|
||||
|
||||
number = NotNaN::from(5.0f64);
|
||||
number += 4.0f64;
|
||||
assert_eq!(*number, 9.0f64);
|
||||
number -= 4.0f64;
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number *= 4.0f64;
|
||||
assert_eq!(*number, 20.0f64);
|
||||
number /= 4.0f64;
|
||||
assert_eq!(*number, 5.0f64);
|
||||
number %= 4.0f64;
|
||||
assert_eq!(*number, 1.0f64);
|
||||
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f64); tmp += f64::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f64); tmp -= f64::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f64); tmp *= f64::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f64); tmp /= f64::NAN;}).is_err());
|
||||
assert!(panic::catch_unwind(|| {let mut tmp = NotNaN::from(0.0f64); tmp %= f64::NAN;}).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
describe! hashing {
|
||||
it "should hash zero and neg-zero to the same hc" {
|
||||
let state = RandomState::new();
|
||||
let mut h1 = state.build_hasher();
|
||||
let mut h2 = state.build_hasher();
|
||||
OrderedFloat::from(0f64).hash(&mut h1);
|
||||
OrderedFloat::from(-0f64).hash(&mut h2);
|
||||
assert_eq!(h1.finish(), h2.finish());
|
||||
}
|
||||
|
||||
it "should hash inf and neg-inf to different hcs" {
|
||||
let state = RandomState::new();
|
||||
let mut h1 = state.build_hasher();
|
||||
let mut h2 = state.build_hasher();
|
||||
OrderedFloat::from(f64::INFINITY).hash(&mut h1);
|
||||
OrderedFloat::from(f64::NEG_INFINITY).hash(&mut h2);
|
||||
assert!(h1.finish() != h2.finish());
|
||||
}
|
||||
|
||||
it "should have a good hash function for whole numbers" {
|
||||
let state = RandomState::new();
|
||||
let limit = 10000;
|
||||
|
||||
let mut set = ::std::collections::HashSet::with_capacity(limit);
|
||||
for i in 0..limit {
|
||||
let mut h = state.build_hasher();
|
||||
OrderedFloat::from(i as f64).hash(&mut h);
|
||||
set.insert(h.finish());
|
||||
}
|
||||
|
||||
// This allows 100 collisions, which is far too
|
||||
// many, but should guard against transient issues
|
||||
// that will result from using RandomState
|
||||
let pct_unique = set.len() as f64 / limit as f64;
|
||||
assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique);
|
||||
}
|
||||
|
||||
it "should have a good hash function for fractional numbers" {
|
||||
let state = RandomState::new();
|
||||
let limit = 10000;
|
||||
|
||||
let mut set = ::std::collections::HashSet::with_capacity(limit);
|
||||
for i in 0..limit {
|
||||
let mut h = state.build_hasher();
|
||||
OrderedFloat::from(i as f64 * (1f64 / limit as f64)).hash(&mut h);
|
||||
set.insert(h.finish());
|
||||
}
|
||||
|
||||
// This allows 100 collisions, which is far too
|
||||
// many, but should guard against transient issues
|
||||
// that will result from using RandomState
|
||||
let pct_unique = set.len() as f64 / limit as f64;
|
||||
assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique);
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{".travis.yml":"dc24c2b07c61ee79ec6190cf2245f9522b86af8468301270fc3d65ffbbe3afd2","Cargo.toml":"54737ed24e861323b4aa09439d84d523126075a5f04c76e8b90107e1b74d6c24","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"9998bb7a1a14ca250c3571ae2beed5905824057359aef2c7f19c8f4aeedc996f","build.rs":"c9fd295a8a84459f29ba6e1460118efab8d02f875d95eccc36d7ca66876f6713","src/atom.rs":"fe85bb6aa6f40dc69ffe0537445ba5dd46f83e93bac95316178d72d01e5b8f7c","src/bench.rs":"c4738a6709ca77e99f174d6c0b640c72c20cbe49a10e4765e4df79882dfd2983","src/event.rs":"b97e45ed554583f7badb83fa751fc2260a87348dc7a4cd4fa00befe345cf7638","src/lib.rs":"0c546862d24fbfedba0192b0e52e00487a76b7a6de5b8a57daa07f108c21c4d9"},"package":"39cb4173bcbd1319da31faa5468a7e3870683d7a237150b0b0aaafd546f6ad12"}
|
||||
{"files":{".travis.yml":"dc24c2b07c61ee79ec6190cf2245f9522b86af8468301270fc3d65ffbbe3afd2","Cargo.toml":"57167143541db9e97ff783f9c4c0569fe120f83bd4c53d12ff34a088bd539248","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"9998bb7a1a14ca250c3571ae2beed5905824057359aef2c7f19c8f4aeedc996f","build.rs":"c9fd295a8a84459f29ba6e1460118efab8d02f875d95eccc36d7ca66876f6713","src/atom.rs":"4613a3226d95d666c5cd0f879305e27e2c20594b6257038065182c50ddc29bdd","src/bench.rs":"c4738a6709ca77e99f174d6c0b640c72c20cbe49a10e4765e4df79882dfd2983","src/event.rs":"b97e45ed554583f7badb83fa751fc2260a87348dc7a4cd4fa00befe345cf7638","src/lib.rs":"0c546862d24fbfedba0192b0e52e00487a76b7a6de5b8a57daa07f108c21c4d9"},"package":"25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "string_cache"
|
||||
version = "0.7.1"
|
||||
version = "0.7.3"
|
||||
authors = ["The Servo Project Developers"]
|
||||
build = "build.rs"
|
||||
description = "A string interning library for Rust, developed as part of the Servo project."
|
||||
|
@ -22,12 +22,12 @@ repository = "https://github.com/servo/string-cache"
|
|||
|
||||
[lib]
|
||||
name = "string_cache"
|
||||
[dependencies.debug_unreachable]
|
||||
version = "0.1.1"
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1"
|
||||
|
||||
[dependencies.new_debug_unreachable]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.phf_shared]
|
||||
version = "0.7.4"
|
||||
|
||||
|
@ -40,7 +40,7 @@ version = "1"
|
|||
[dependencies.string_cache_shared]
|
||||
version = "0.3"
|
||||
[dev-dependencies.rand]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
[build-dependencies.string_cache_codegen]
|
||||
version = "0.4"
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
use phf_shared;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[allow(unused_imports)] use std::ascii::AsciiExt;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering::{self, Equal};
|
||||
use std::fmt;
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"180cc837b1ea2ce0ed737c2e15208e83abf6f92291a77ed1ebcc564c628c2077","Cargo.toml":"cc09349f0610a327f3562a4c44b9c3889e5a9bf43c290ce436bfb98a4e66b0ed","README.md":"447088161e4b8c6060ae830d41ba2adf3cac2dbd8b1195c618b062878832be82","src/lib.rs":"2cb4bbb6a0c7058e49f5bbc0c1e2f208b5374cf70c495813401a357f9dfad188"},"package":"1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"}
|
|
@ -1,19 +0,0 @@
|
|||
language: rust
|
||||
sudo: false
|
||||
|
||||
script:
|
||||
- cargo build
|
||||
- cargo test
|
||||
- cargo bench --no-run
|
||||
- cargo doc
|
||||
|
||||
after_success:
|
||||
- if [ "$TRAVIS_PULL_REQUEST" == false && test == "TRAVIS_BRANCH" == "master" ]; then
|
||||
- curl https://raw.githubusercontent.com/reem/rust-gh-docs/master/make-docs.sh > docs.sh
|
||||
- chmod u+x docs.sh
|
||||
- ./docs.sh reem project-name
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: QPYL1XUr4CyK/2DXlsYC1eCpWRpyEiqQSd/FFVR+YdP/rOJ7AyAXQqPhfgjDBQwvc6E2fUiyYjoV/xe1a757DDeZKlgd8Lp20fSDwvNt/Ejx8ueh3h3kuOtgDpIGSKX/l+XC+ltDpzjhh7bowI2/fOEf+kE53jvu9i4PiLnKdlY=
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
[package]
|
||||
|
||||
name = "unreachable"
|
||||
version = "0.1.1"
|
||||
authors = ["Jonathan Reem <jonathan.reem@gmail.com>"]
|
||||
repository = "https://github.com/reem/rust-unreachable.git"
|
||||
description = "An unreachable code optimization hint in stable rust."
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies.void]
|
||||
version = "1"
|
||||
default-features = false
|
|
@ -1,24 +0,0 @@
|
|||
# unreachable
|
||||
|
||||
> An unreachable code optimization hint in stable rust.
|
||||
|
||||
## [Documentation](https://crates.fyi/crates/unreachable/0.1.1)
|
||||
|
||||
## Usage
|
||||
|
||||
Use the crates.io repository; add this to your `Cargo.toml` along
|
||||
with the rest of your dependencies:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
unreachable = "0.1"
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
[Jonathan Reem](https://medium.com/@jreem) is the primary author and maintainer of unreachable.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#![cfg_attr(test, deny(warnings))]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! # unreachable
|
||||
//!
|
||||
//! An unreachable code optimization hint in stable rust, and some useful
|
||||
//! extension traits for `Option` and `Result`.
|
||||
//!
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate void;
|
||||
|
||||
use core::mem;
|
||||
|
||||
/// Hint to the optimizer that any code path which calls this function is
|
||||
/// statically unreachable and can be removed.
|
||||
///
|
||||
/// Calling this function in reachable code invokes undefined behavior. Be
|
||||
/// very, very sure this is what you want; often, a simple `panic!` is more
|
||||
/// suitable.
|
||||
#[inline]
|
||||
pub unsafe fn unreachable() -> ! {
|
||||
let x: &void::Void = mem::transmute(1usize);
|
||||
void::unreachable(*x)
|
||||
}
|
||||
|
||||
/// An extension trait for `Option<T>` providing unchecked unwrapping methods.
|
||||
pub trait UncheckedOptionExt<T> {
|
||||
/// Get the value out of this Option without checking for None.
|
||||
unsafe fn unchecked_unwrap(self) -> T;
|
||||
|
||||
/// Assert that this Option is a None to the optimizer.
|
||||
unsafe fn unchecked_unwrap_none(self);
|
||||
}
|
||||
|
||||
/// An extension trait for `Result<T, E>` providing unchecked unwrapping methods.
|
||||
pub trait UncheckedResultExt<T, E> {
|
||||
/// Get the value out of this Result without checking for Err.
|
||||
unsafe fn unchecked_unwrap_ok(self) -> T;
|
||||
|
||||
/// Get the error out of this Result without checking for Ok.
|
||||
unsafe fn unchecked_unwrap_err(self) -> E;
|
||||
}
|
||||
|
||||
impl<T> UncheckedOptionExt<T> for Option<T> {
|
||||
unsafe fn unchecked_unwrap(self) -> T {
|
||||
match self {
|
||||
Some(x) => x,
|
||||
None => unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn unchecked_unwrap_none(self) {
|
||||
match self {
|
||||
Some(_) => unreachable(),
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> UncheckedResultExt<T, E> for Result<T, E> {
|
||||
unsafe fn unchecked_unwrap_ok(self) -> T {
|
||||
match self {
|
||||
Ok(x) => x,
|
||||
Err(_) => unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn unchecked_unwrap_err(self) -> E {
|
||||
match self {
|
||||
Ok(_) => unreachable(),
|
||||
Err(e) => e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче