summaryrefslogtreecommitdiffstats
path: root/vendor/cassowary-0.3.0
diff options
context:
space:
mode:
authorEllie Huxtable <e@elm.sh>2021-05-17 19:51:09 +0100
committerEllie Huxtable <e@elm.sh>2021-05-17 19:51:09 +0100
commitd0215a937a7889a97e11778ee4b0f9a12de01278 (patch)
tree5a8fd5ad62e6b5a4c218746ff2d4bd97373a48de /vendor/cassowary-0.3.0
parent802a2258cbd839c5b82d24f74d7aebe4a27d8dc5 (diff)
Vendor dependenciesvendor
Just testing how CI works with this. I tend to prefer vendoring, as it means that if you have a copy of the code *you can always build it*. Even if you're 20 years in the future This is the output of ``` cargo vendor --versioned-dirs ```
Diffstat (limited to 'vendor/cassowary-0.3.0')
-rw-r--r--vendor/cassowary-0.3.0/.cargo-checksum.json1
-rw-r--r--vendor/cassowary-0.3.0/CHANGELOG.md18
-rw-r--r--vendor/cassowary-0.3.0/Cargo.toml25
-rw-r--r--vendor/cassowary-0.3.0/LICENSE-APACHE201
-rw-r--r--vendor/cassowary-0.3.0/LICENSE-MIT21
-rw-r--r--vendor/cassowary-0.3.0/README.md54
-rw-r--r--vendor/cassowary-0.3.0/src/lib.rs623
-rw-r--r--vendor/cassowary-0.3.0/src/operators.rs561
-rw-r--r--vendor/cassowary-0.3.0/src/solver_impl.rs784
-rw-r--r--vendor/cassowary-0.3.0/tests/common/mod.rs35
-rw-r--r--vendor/cassowary-0.3.0/tests/quadrilateral.rs106
-rw-r--r--vendor/cassowary-0.3.0/tests/removal.rs30
12 files changed, 2459 insertions, 0 deletions
diff --git a/vendor/cassowary-0.3.0/.cargo-checksum.json b/vendor/cassowary-0.3.0/.cargo-checksum.json
new file mode 100644
index 00000000..9fb95682
--- /dev/null
+++ b/vendor/cassowary-0.3.0/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"3a9b7f3f8bb314b2f5f7fcd3504e249f69f95765a9800d613b8e9762a4d8855e","Cargo.toml":"9ab348a432e2a3b62ff6c8213db8000e61206d04b9e12ac7e29355bb92093079","LICENSE-APACHE":"38b4da6afcf8d01bf9fae5b09dc5446a4e166556b7d66f3ba03305f6c05188ed","LICENSE-MIT":"190ca8d01e23551e4f49e9601a2ca1a740a4a3a9270ad3b5c70f044b8972ef50","README.md":"1654f0b6cd68714752dc60e4386431808e790a69f70f1c3d5524d44a2bd6ae57","src/lib.rs":"1b5b92de9a5f6d7dfc807bf0a618b6175ea8bc894c58d4b77d46cff7849ed6e2","src/operators.rs":"820b4fcffab885883ba9900a12da31e858014280fc226756635eafb7f671cdda","src/solver_impl.rs":"ebde682191f4f5f9aba0b193a25ace54fd25d07facec10fca58a9883dcf794b2","tests/common/mod.rs":"29648db4ecd903a19fffceff5da00bf6707750adc2ceefa350d3adbd95a3eca2","tests/quadrilateral.rs":"411502da8e70f49d474c81e8d43520500880552e45eaefe652145578e7f7add9","tests/removal.rs":"8e0f45ad6ea55315f105973fc78aa4e1546d0a0816d7be12999afd8b75b7efd0"},"package":"df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"} \ No newline at end of file
diff --git a/vendor/cassowary-0.3.0/CHANGELOG.md b/vendor/cassowary-0.3.0/CHANGELOG.md
new file mode 100644
index 00000000..f1385db0
--- /dev/null
+++ b/vendor/cassowary-0.3.0/CHANGELOG.md
@@ -0,0 +1,18 @@
+# 0.3
+
+* Various fixes (PR #4) from @christolliday.
+ Main breaking change is that variables no longer silently initialise to zero and will report
+ their initial value in the first call to `fetch_changes`, also `has_edit_variable` now takes `&self`
+ instead of `&mut self`.
+
+## 0.2.1
+
+* Fixed crash under certain use cases. See PR #1 (Thanks @christolliday!).
+
+# 0.2.0
+
+* Changed API to only report changes to the values of variables. This allows for more efficient use of the library in typical applications.
+
+# 0.1
+
+Initial release
diff --git a/vendor/cassowary-0.3.0/Cargo.toml b/vendor/cassowary-0.3.0/Cargo.toml
new file mode 100644
index 00000000..31b2abb8
--- /dev/null
+++ b/vendor/cassowary-0.3.0/Cargo.toml
@@ -0,0 +1,25 @@
+# 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 = "cassowary"
+version = "0.3.0"
+authors = ["Dylan Ede <dylanede@googlemail.com>"]
+description = "A Rust implementation of the Cassowary linear constraint solving algorithm.\n\nThe Cassowary algorithm is designed for naturally laying out user interfaces using linear constraints,\nlike 'this button must line up with this text box'.\n"
+homepage = "https://github.com/dylanede/cassowary-rs"
+documentation = "https://dylanede.github.io/cassowary-rs"
+readme = "README.md"
+keywords = ["constraint", "simplex", "user", "interface", "layout"]
+license = "MIT / Apache-2.0"
+repository = "https://github.com/dylanede/cassowary-rs"
+
+[dependencies]
diff --git a/vendor/cassowary-0.3.0/LICENSE-APACHE b/vendor/cassowary-0.3.0/LICENSE-APACHE
new file mode 100644
index 00000000..462333df
--- /dev/null
+++ b/vendor/cassowary-0.3.0/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/cassowary-0.3.0/LICENSE-MIT b/vendor/cassowary-0.3.0/LICENSE-MIT
new file mode 100644
index 00000000..e8d11a44
--- /dev/null
+++ b/vendor/cassowary-0.3.0/LICENSE-MIT
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Dylan Ede
+
+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.
diff --git a/vendor/cassowary-0.3.0/README.md b/vendor/cassowary-0.3.0/README.md
new file mode 100644
index 00000000..ba38947a
--- /dev/null
+++ b/vendor/cassowary-0.3.0/README.md
@@ -0,0 +1,54 @@
+# cassowary-rs
+
+[![Build Status](https://travis-ci.org/dylanede/cassowary-rs.svg?branch=master)](https://travis-ci.org/dylanede/cassowary-rs)
+
+This is a Rust implementation of the Cassowary constraint solving algorithm
+([Badros et. al 2001](https://constraints.cs.washington.edu/solvers/cassowary-tochi.pdf)).
+It is based heavily on the implementation for C++ at
+[nucleic/kiwi](https://github.com/nucleic/kiwi). The implementation does
+however differ in some details.
+
+Cassowary is designed for solving constraints to lay out user interfaces.
+Constraints typically take the form "this button must line up with this
+text box", or "this box should try to be 3 times the size of this other box".
+Its most popular incarnation by far is in Apple's Autolayout
+system for Mac OS X and iOS user interfaces. UI libraries using the Cassowary
+algorithm manage to achieve a much more natural approach to specifying UI
+layouts than traditional approaches like those found in HTML.
+
+This library is a low level interface to the solving algorithm, though it
+tries to be as convenient as possible. As a result it does not have any
+intrinsic knowledge of common user interface conventions like rectangular
+regions or even two dimensions. These abstractions belong in a higher level
+crate.
+
+For more information, please read
+**[the documentation](https://dylanede.github.io/cassowary-rs)**.
+
+## Getting Started
+
+Add the following to your Cargo.toml:
+
+```toml
+[dependencies]
+cassowary = "^0.3.0"
+```
+
+Please read the documentation (linked above) for how to best use this crate.
+
+## License
+
+Licensed under either of
+
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
+ http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or
+ http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
diff --git a/vendor/cassowary-0.3.0/src/lib.rs b/vendor/cassowary-0.3.0/src/lib.rs
new file mode 100644
index 00000000..b1ab8fcb
--- /dev/null
+++ b/vendor/cassowary-0.3.0/src/lib.rs
@@ -0,0 +1,623 @@
+//! This crate contains an implementation of the Cassowary constraint solving algorithm, based upon the work by
+//! G.J. Badros et al. in 2001. This algorithm is designed primarily for use constraining elements in user interfaces.
+//! Constraints are linear combinations of the problem variables. The notable features of Cassowary that make it
+//! ideal for user interfaces are that it is incremental (i.e. you can add and remove constraints at runtime
+//! and it will perform the minimum work to update the result) and that the constraints can be violated if
+//! necessary,
+//! with the order in which they are violated specified by setting a "strength" for each constraint.
+//! This allows the solution to gracefully degrade, which is useful for when a
+//! user interface needs to compromise on its constraints in order to still be able to display something.
+//!
+//! ## Constraint syntax
+//!
+//! This crate aims to provide syntax for describing linear constraints as naturally as possible, within
+//! the limitations of Rust's type system. Generally you can write constraints as you would naturally, however
+//! the operator symbol (for greater-than, less-than, equals) is replaced with an instance of the
+//! `WeightedRelation` enum wrapped in "pipe brackets".
+//!
+//! For example, for the constraint
+//! `(a + b) * 2 + c >= d + 1` with strength `s`, the code to use is
+//!
+//! ```ignore
+//! (a + b) * 2.0 + c |GE(s)| d + 1.0
+//! ```
+//!
+//! # A simple example
+//!
+//! Imagine a layout consisting of two elements laid out horizontally. For small window widths the elements
+//! should compress to fit, but if there is enough space they should display at their preferred widths. The
+//! first element will align to the left, and the second to the right. For this example we will ignore
+//! vertical layout.
+//!
+//! First we need to include the relevant parts of `cassowary`:
+//!
+//! ```
+//! use cassowary::{ Solver, Variable };
+//! use cassowary::WeightedRelation::*;
+//! use cassowary::strength::{ WEAK, MEDIUM, STRONG, REQUIRED };
+//! ```
+//!
+//! And we'll construct some conveniences for pretty printing (which should hopefully be self-explanatory):
+//!
+//! ```ignore
+//! use std::collections::HashMap;
+//! let mut names = HashMap::new();
+//! fn print_changes(names: &HashMap<Variable, &'static str>, changes: &[(Variable, f64)]) {
+//! println!("Changes:");
+//! for &(ref var, ref val) in changes {
+//! println!("{}: {}", names[var], val);
+//! }
+//! }
+//! ```
+//!
+//! Let's define the variables required - the left and right edges of the elements, and the width of the window.
+//!
+//! ```ignore
+//! let window_width = Variable::new();
+//! names.insert(window_width, "window_width");
+//!
+//! struct Element {
+//! left: Variable,
+//! right: Variable
+//! }
+//! let box1 = Element {
+//! left: Variable::new(),
+//! right: Variable::new()
+//! };
+//! names.insert(box1.left, "box1.left");
+//! names.insert(box1.right, "box1.right");
+//!
+//! let box2 = Element {
+//! left: Variable::new(),
+//! right: Variable::new()
+//! };
+//! names.insert(box2.left, "box2.left");
+//! names.insert(box2.right, "box2.right");
+//! ```
+//!
+//! Now to set up the solver and constraints.
+//!
+//! ```ignore
+//! let mut solver = Solver::new();
+//! solver.add_constraints(&[window_width |GE(REQUIRED)| 0.0, // positive window width
+//! box1.left |EQ(REQUIRED)| 0.0, // left align
+//! box2.right |EQ(REQUIRED)| window_width, // right align
+//! box2.left |GE(REQUIRED)| box1.right, // no overlap
+//! // positive widths
+//! box1.left |LE(REQUIRED)| box1.right,
+//! box2.left |LE(REQUIRED)| box2.right,
+//! // preferred widths:
+//! box1.right - box1.left |EQ(WEAK)| 50.0,
+//! box2.right - box2.left |EQ(WEAK)| 100.0]).unwrap();
+//! ```
+//!
+//! The window width is currently free to take any positive value. Let's constrain it to a particular value.
+//! Since for this example we will repeatedly change the window width, it is most efficient to use an
+//! "edit variable", instead of repeatedly removing and adding constraints (note that for efficiency
+//! reasons we cannot edit a normal constraint that has been added to the solver).
+//!
+//! ```ignore
+//! solver.add_edit_variable(window_width, STRONG).unwrap();
+//! solver.suggest_value(window_width, 300.0).unwrap();
+//! ```
+//!
+//! This value of 300 is enough to fit both boxes in with room to spare, so let's check that this is the case.
+//! We can fetch a list of changes to the values of variables in the solver. Using the pretty printer defined
+//! earlier we can see what values our variables now hold.
+//!
+//! ```ignore
+//! print_changes(&names, solver.fetch_changes());
+//! ```
+//!
+//! This should print (in a possibly different order):
+//!
+//! ```ignore
+//! Changes:
+//! window_width: 300
+//! box1.right: 50
+//! box2.left: 200
+//! box2.right: 300
+//! ```
+//!
+//! Note that the value of `box1.left` is not mentioned. This is because `solver.fetch_changes` only lists
+//! *changes* to variables, and since each variable starts in the solver with a value of zero, any values that
+//! have not changed from zero will not be reported.
+//!
+//! Now let's try compressing the window so that the boxes can't take up their preferred widths.
+//!
+//! ```ignore
+//! solver.suggest_value(window_width, 75.0);
+//! print_changes(&names, solver.fetch_changes);
+//! ```
+//!
+//! Now the solver can't satisfy all of the constraints. It will pick at least one of the weakest constraints to
+//! violate. In this case it will be one or both of the preferred widths. For efficiency reasons this is picked
+//! nondeterministically, so there are two possible results. This could be
+//!
+//! ```ignore
+//! Changes:
+//! window_width: 75
+//! box1.right: 0
+//! box2.left: 0
+//! box2.right: 75
+//! ```
+//!
+//! or
+//!
+//! ```ignore
+//! Changes:
+//! window_width: 75
+//! box2.left: 50
+//! box2.right: 75
+//! ```
+//!
+//! Due to the nature of the algorithm, "in-between" solutions, although just as valid, are not picked.
+//!
+//! In a user interface this is not likely a result we would prefer. The solution is to add another constraint
+//! to control the behaviour when the preferred widths cannot both be satisfied. In this example we are going
+//! to constrain the boxes to try to maintain a ratio between their widths.
+//!
+//! ```
+//! # use cassowary::{ Solver, Variable };
+//! # use cassowary::WeightedRelation::*;
+//! # use cassowary::strength::{ WEAK, MEDIUM, STRONG, REQUIRED };
+//! #
+//! # use std::collections::HashMap;
+//! # let mut names = HashMap::new();
+//! # fn print_changes(names: &HashMap<Variable, &'static str>, changes: &[(Variable, f64)]) {
+//! # println!("Changes:");
+//! # for &(ref var, ref val) in changes {
+//! # println!("{}: {}", names[var], val);
+//! # }
+//! # }
+//! #
+//! # let window_width = Variable::new();
+//! # names.insert(window_width, "window_width");
+//! # struct Element {
+//! # left: Variable,
+//! # right: Variable
+//! # }
+//! # let box1 = Element {
+//! # left: Variable::new(),
+//! # right: Variable::new()
+//! # };
+//! # names.insert(box1.left, "box1.left");
+//! # names.insert(box1.right, "box1.right");
+//! # let box2 = Element {
+//! # left: Variable::new(),
+//! # right: Variable::new()
+//! # };
+//! # names.insert(box2.left, "box2.left");
+//! # names.insert(box2.right, "box2.right");
+//! # let mut solver = Solver::new();
+//! # solver.add_constraints(&[window_width |GE(REQUIRED)| 0.0, // positive window width
+//! # box1.left |EQ(REQUIRED)| 0.0, // left align
+//! # box2.right |EQ(REQUIRED)| window_width, // right align
+//! # box2.left |GE(REQUIRED)| box1.right, // no overlap
+//! # // positive widths
+//! # box1.left |LE(REQUIRED)| box1.right,
+//! # box2.left |LE(REQUIRED)| box2.right,
+//! # // preferred widths:
+//! # box1.right - box1.left |EQ(WEAK)| 50.0,
+//! # box2.right - box2.left |EQ(WEAK)| 100.0]).unwrap();
+//! # solver.add_edit_variable(window_width, STRONG).unwrap();
+//! # solver.suggest_value(window_width, 300.0).unwrap();
+//! # print_changes(&names, solver.fetch_changes());
+//! # solver.suggest_value(window_width, 75.0);
+//! # print_changes(&names, solver.fetch_changes());
+//! solver.add_constraint(
+//! (box1.right - box1.left) / 50.0 |EQ(MEDIUM)| (box2.right - box2.left) / 100.0
+//! ).unwrap();
+//! print_changes(&names, solver.fetch_changes());
+//! ```
+//!
+//! Now the result gives values that maintain the ratio between the sizes of the two boxes:
+//!
+//! ```ignore
+//! Changes:
+//! box1.right: 25
+//! box2.left: 25
+//! ```
+//!
+//! This example may have appeared somewhat contrived, but hopefully it shows the power of the cassowary
+//! algorithm for laying out user interfaces.
+//!
+//! One thing that this example exposes is that this crate is a rather low level library. It does not have
+//! any inherent knowledge of user interfaces, directions or boxes. Thus for use in a user interface this
+//! crate should ideally be wrapped by a higher level API, which is outside the scope of this crate.
+use std::sync::Arc;
+use std::collections::HashMap;
+use std::collections::hash_map::{Entry};
+
+mod solver_impl;
+mod operators;
+
+static VARIABLE_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT;
+
+/// Identifies a variable for the constraint solver.
+/// Each new variable is unique in the view of the solver, but copying or cloning the variable produces
+/// a copy of the same variable.
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct Variable(usize);
+
+impl Variable {
+ /// Produces a new unique variable for use in constraint solving.
+ pub fn new() -> Variable {
+ Variable(VARIABLE_ID.fetch_add(1, ::std::sync::atomic::Ordering::Relaxed))
+ }
+}
+
+/// A variable and a coefficient to multiply that variable by. This is a sub-expression in
+/// a constraint equation.
+#[derive(Copy, Clone, Debug)]
+pub struct Term {
+ pub variable: Variable,
+ pub coefficient: f64
+}
+
+impl Term {
+ /// Construct a new Term from a variable and a coefficient.
+ fn new(variable: Variable, coefficient: f64) -> Term {
+ Term {
+ variable: variable,
+ coefficient: coefficient
+ }
+ }
+}
+
+/// An expression that can be the left hand or right hand side of a constraint equation.
+/// It is a linear combination of variables, i.e. a sum of variables weighted by coefficients, plus an optional constant.
+#[derive(Clone, Debug)]
+pub struct Expression {
+ pub terms: Vec<Term>,
+ pub constant: f64
+}
+
+impl Expression {
+ /// Constructs an expression of the form _n_, where n is a constant real number, not a variable.
+ pub fn from_constant(v: f64) -> Expression {
+ Expression {
+ terms: Vec::new(),
+ constant: v
+ }
+ }
+ /// Constructs an expression from a single term. Forms an expression of the form _n x_
+ /// where n is the coefficient, and x is the variable.
+ pub fn from_term(term: Term) -> Expression {
+ Expression {
+ terms: vec![term],
+ constant: 0.0
+ }
+ }
+ /// General constructor. Each `Term` in `terms` is part of the sum forming the expression, as well as `constant`.
+ pub fn new(terms: Vec<Term>, constant: f64) -> Expression {
+ Expression {
+ terms: terms,
+ constant: constant
+ }
+ }
+ /// Mutates this expression by multiplying it by minus one.
+ pub fn negate(&mut self) {
+ self.constant = -self.constant;
+ for t in &mut self.terms {
+ *t = -*t;
+ }
+ }
+}
+
+impl From<f64> for Expression {
+ fn from(v: f64) -> Expression {
+ Expression::from_constant(v)
+ }
+}
+
+impl From<Variable> for Expression {
+ fn from(v: Variable) -> Expression {
+ Expression::from_term(Term::new(v, 1.0))
+ }
+}
+
+impl From<Term> for Expression {
+ fn from(t: Term) -> Expression {
+ Expression::from_term(t)
+ }
+}
+
+/// Contains useful constants and functions for producing strengths for use in the constraint solver.
+/// Each constraint added to the solver has an associated strength specifying the precedence the solver should
+/// impose when choosing which constraints to enforce. It will try to enforce all constraints, but if that
+/// is impossible the lowest strength constraints are the first to be violated.
+///
+/// Strengths are simply real numbers. The strongest legal strength is 1,001,001,000.0. The weakest is 0.0.
+/// For convenience constants are declared for commonly used strengths. These are `REQUIRED`, `STRONG`,
+/// `MEDIUM` and `WEAK`. Feel free to multiply these by other values to get intermediate strengths.
+/// Note that the solver will clip given strengths to the legal range.
+///
+/// `REQUIRED` signifies a constraint that cannot be violated under any circumstance. Use this special strength
+/// sparingly, as the solver will fail completely if it find that not all of the `REQUIRED` constraints
+/// can be satisfied. The other strengths represent fallible constraints. These should be the most
+/// commonly used strenghts for use cases where violating a constraint is acceptable or even desired.
+///
+/// The solver wil