├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md ├── rsx-arena ├── Cargo.toml └── src │ ├── common.rs │ ├── hashmap │ ├── arena.rs │ ├── bucket.rs │ └── mod.rs │ ├── lib.rs │ ├── util.rs │ └── vec │ ├── arena.rs │ └── mod.rs ├── rsx-dom ├── Cargo.toml ├── src │ ├── convert.rs │ ├── export.rs │ ├── graph │ │ ├── mod.rs │ │ ├── node_id.rs │ │ ├── node_ref.rs │ │ ├── node_ref_mut.rs │ │ ├── node_ref_mut_pair.rs │ │ └── tree.rs │ ├── lib.rs │ ├── macros.rs │ ├── types.rs │ └── util.rs └── tests │ ├── spec_quote.rs │ └── spec_runtime.rs ├── rsx-tree ├── Cargo.toml └── src │ ├── iter.rs │ ├── lib.rs │ ├── node.rs │ ├── node_id.rs │ ├── node_ref.rs │ ├── node_ref_mut.rs │ ├── node_ref_mut_pair.rs │ └── tree.rs ├── rust-toolchain └── rustfmt.toml /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | Cargo.lock 3 | **/*.rs.bk 4 | .vscode 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | os: 3 | - linux 4 | # - osx 5 | rust: 6 | - nightly 7 | notifications: 8 | email: false 9 | before_script: 10 | - cargo +nightly install rustfmt-nightly --vers 0.3.8 --force 11 | - cargo +nightly install clippy --force 12 | - export PATH=$PATH:~/.cargo/bin 13 | script: 14 | - cargo build --verbose 15 | - cargo test --verbose 16 | - cargo +nightly fmt --all -- --write-mode=diff 17 | - cargo +nightly clippy --all -- --deny warnings 18 | after_success: 19 | - | 20 | if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" ]]; then 21 | cargo doc && 22 | echo "" > target/doc/index.html && 23 | git clone https://github.com/davisp/ghp-import.git && 24 | ./ghp-import/ghp_import.py -n -p -f -m "Documentation upload" -r https://"$GH_TOKEN"@github.com/"$TRAVIS_REPO_SLUG.git" target/doc && 25 | echo "Uploaded documentation" 26 | fi 27 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "rsx-arena", 4 | "rsx-tree", 5 | "rsx-dom" 6 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Under heavy research and development, please don't use this yet!** 2 | 3 | # rsx-dom 4 | [![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0) 5 | [![Build Status](https://travis-ci.org/victorporof/rsx-dom.svg?branch=master)](https://travis-ci.org/victorporof/rsx-dom) 6 | 7 | Simple node tree abstraction layer over RSX syntax trees 8 | 9 | ## Purpose 10 | A backwards compatible higher level of abstraction over the AST generated by the [RSX parser](https://github.com/victorporof/rsx-parser). Since working directly with `rsx_parser::RSXElement` abstract syntax trees (or Rust's [proc_macro::TokenStream](https://doc.rust-lang.org/proc_macro/struct.TokenStream.html)) can be tedious, and the underlying parser and compiler data formats can change at any time, a simpler DOM structure is useful as an abstraction layer in the scope of writing [RSX code](https://github.com/victorporof/rsx-compiler-plugin). 11 | 12 | ## How to use 13 | [Documentation](https://victorporof.github.io/rsx-dom) 14 | 15 | This crate concerns itself strictly generating a DOM node tree from a RSX syntax tree. If you're just looking to write RSX in your project, take a look at the [RSX compiler plugin](https://github.com/victorporof/rsx_compiler_plugin) instead. 16 | 17 | Otherwise, add this to your `Cargo.toml` file: 18 | 19 | ```toml 20 | [dependencies] 21 | rsx-dom = { git = "https://github.com/victorporof/rsx-dom.git" } 22 | ``` 23 | 24 | RSX parsing is enabled via the `rsx-parse` feature gate. 25 | 26 | ```toml 27 | [dependencies] 28 | rsx-dom = { git = "https://github.com/victorporof/rsx-dom.git", features = ["rsx-parse"] } 29 | ``` 30 | 31 | When used as part of the [RSX compiler plugin](https://github.com/victorporof/rsx_compiler_plugin), the convertion is automatic between `rsx_parser::RSXElement` abstract syntax trees to the more convenient `rsx_dom::DOMNode` elements, because the AST is directly tokenized into a DOM tree to avoid any runtime work! Templating is thus a zero cost abstraction. 32 | 33 | If manual instantiation is desired, simply import the library into your code to build `rsx_dom::DOMNode` elements. 34 | 35 | ```rust 36 | extern crate rsx_dom; 37 | use rsx_dom::types::DOMNode; 38 | 39 | let node = DOMNode::from(...); 40 | ``` 41 | 42 | Note that when used as a compiler plugin, 43 | 44 | *Note: `rsx-dom` also re-exports the `rsx-parser` [crate](https://github.com/victorporof/rsx-parser), only needed if you need to parse character streams (such as strings) directly. You'll probably prefer using the `rsx!` macro as part of the [RSX compiler plugin](https://github.com/victorporof/rsx_compiler_plugin) instead.* 45 | 46 | See all the available [types](https://github.com/victorporof/rsx-parser/blob/master/src/parse_elements_types.rs) for more details. 47 | -------------------------------------------------------------------------------- /rsx-arena/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsx-arena" 3 | version = "0.1.0" 4 | authors = ["Victor Porof "] 5 | 6 | [lib] 7 | name = "rsx_arena" 8 | 9 | [dependencies] 10 | fnv = "1.0.6" 11 | num-traits = "0.2.0" 12 | smallvec = "0.6.0" 13 | -------------------------------------------------------------------------------- /rsx-arena/src/common.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::fmt; 13 | use std::hash::{Hash, Hasher}; 14 | use std::marker::PhantomData; 15 | use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; 16 | 17 | use num_traits::{FromPrimitive, ToPrimitive}; 18 | 19 | #[derive(PartialOrd, Ord)] 20 | pub(crate) struct BucketId(u32, PhantomData); 21 | 22 | impl fmt::Debug for BucketId { 23 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 24 | write!(f, "BucketId({})", self.0) 25 | } 26 | } 27 | 28 | impl Eq for BucketId {} 29 | 30 | impl PartialEq for BucketId { 31 | fn eq(&self, other: &Self) -> bool { 32 | self.0 == other.0 33 | } 34 | } 35 | 36 | impl Copy for BucketId {} 37 | 38 | impl Clone for BucketId { 39 | fn clone(&self) -> BucketId { 40 | *self 41 | } 42 | } 43 | 44 | impl Hash for BucketId { 45 | fn hash(&self, hasher: &mut H) { 46 | self.0.hash(hasher); 47 | } 48 | } 49 | 50 | impl BucketId { 51 | pub(crate) fn new(value: u32) -> Self { 52 | BucketId(value, PhantomData) 53 | } 54 | 55 | pub(crate) fn generate() -> Self { 56 | static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT; 57 | BucketId::new(NEXT_ID.fetch_add(1, Ordering::Relaxed) as u32) 58 | } 59 | } 60 | 61 | #[derive(PartialOrd, Ord)] 62 | pub(crate) struct EntryId(u32, PhantomData); 63 | 64 | impl fmt::Debug for EntryId { 65 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 66 | write!(f, "EntryId({})", self.0) 67 | } 68 | } 69 | 70 | impl Eq for EntryId {} 71 | 72 | impl PartialEq for EntryId { 73 | fn eq(&self, other: &Self) -> bool { 74 | self.0 == other.0 75 | } 76 | } 77 | 78 | impl Copy for EntryId {} 79 | 80 | impl Clone for EntryId { 81 | fn clone(&self) -> EntryId { 82 | *self 83 | } 84 | } 85 | 86 | impl Hash for EntryId { 87 | fn hash(&self, hasher: &mut H) { 88 | self.0.hash(hasher); 89 | } 90 | } 91 | 92 | impl EntryId { 93 | pub(crate) fn new(value: u32) -> Self { 94 | EntryId(value, PhantomData) 95 | } 96 | 97 | pub(crate) fn generate(&mut self) -> Self { 98 | let index = self.0; 99 | self.0 += 1; 100 | EntryId::new(index) 101 | } 102 | 103 | pub(crate) fn to_index(&self) -> usize { 104 | self.0 as usize 105 | } 106 | } 107 | 108 | #[derive(PartialOrd, Ord)] 109 | pub struct ArenaItemId { 110 | pub(crate) bucket_id: BucketId, 111 | pub(crate) entry_id: EntryId 112 | } 113 | 114 | impl fmt::Debug for ArenaItemId { 115 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 116 | write!(f, "ArenaItemId({:?}, {:?})", self.bucket_id, self.entry_id) 117 | } 118 | } 119 | 120 | impl Eq for ArenaItemId {} 121 | 122 | impl PartialEq for ArenaItemId { 123 | fn eq(&self, other: &Self) -> bool { 124 | self.bucket_id == other.bucket_id && self.entry_id == other.entry_id 125 | } 126 | } 127 | 128 | impl Copy for ArenaItemId {} 129 | 130 | impl Clone for ArenaItemId { 131 | fn clone(&self) -> ArenaItemId { 132 | *self 133 | } 134 | } 135 | 136 | impl Hash for ArenaItemId { 137 | fn hash(&self, hasher: &mut H) { 138 | self.bucket_id.hash(hasher); 139 | self.entry_id.hash(hasher); 140 | } 141 | } 142 | 143 | impl ToPrimitive for ArenaItemId { 144 | fn to_i64(&self) -> Option { 145 | None 146 | } 147 | 148 | fn to_u64(&self) -> Option { 149 | let bucket_id = u64::from(self.bucket_id.0); 150 | let entry_id = u64::from(self.entry_id.0); 151 | Some(bucket_id << 32 | entry_id) 152 | } 153 | } 154 | 155 | impl FromPrimitive for ArenaItemId { 156 | fn from_i64(_: i64) -> Option { 157 | None 158 | } 159 | 160 | fn from_u64(value: u64) -> Option { 161 | let bucket_id = BucketId::new(((value >> 32) & 0xffff_ffff) as u32); 162 | let entry_id = EntryId::new((value & 0xffff_ffff) as u32); 163 | Some(ArenaItemId { 164 | bucket_id, 165 | entry_id 166 | }) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /rsx-arena/src/hashmap/arena.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::ops::AddAssign; 13 | 14 | use smallvec::SmallVec; 15 | 16 | use hashmap::bucket::HashmapBucket; 17 | use types::ArenaItemId; 18 | use util::as_mut; 19 | 20 | #[derive(Debug, PartialEq)] 21 | pub struct HashmapArena { 22 | buckets: SmallVec<[HashmapBucket; 1]> 23 | } 24 | 25 | impl Default for HashmapArena { 26 | fn default() -> Self { 27 | HashmapArena { 28 | buckets: SmallVec::from_buf([HashmapBucket::new()]) 29 | } 30 | } 31 | } 32 | 33 | impl HashmapArena { 34 | pub fn new() -> Self { 35 | HashmapArena::default() 36 | } 37 | 38 | pub fn alloc(&mut self, value: T) -> ArenaItemId { 39 | self.buckets[0].alloc(value) 40 | } 41 | 42 | pub fn dealloc(&mut self, id: ArenaItemId) -> Option { 43 | self.buckets.iter_mut().find(|v| v.owns(id))?.dealloc(id) 44 | } 45 | 46 | #[inline] 47 | pub fn get(&self, id: ArenaItemId) -> Option<&T> { 48 | self.buckets.iter().find(|v| v.owns(id))?.get(id) 49 | } 50 | 51 | #[inline] 52 | pub fn get_mut(&mut self, id: ArenaItemId) -> Option<&mut T> { 53 | self.buckets.iter_mut().find(|v| v.owns(id))?.get_mut(id) 54 | } 55 | 56 | #[inline] 57 | pub unsafe fn get_as_mut<'a>(&mut self, id: ArenaItemId) -> Option<&'a mut T> { 58 | as_mut(self.get_mut(id)) 59 | } 60 | 61 | #[inline] 62 | pub fn get_mut_pair(&mut self, first_id: ArenaItemId, second_id: ArenaItemId) -> (Option<&mut T>, Option<&mut T>) { 63 | assert_ne!(first_id, second_id); 64 | let first = unsafe { self.get_as_mut(first_id) }; 65 | let second = unsafe { self.get_as_mut(second_id) }; 66 | (first, second) 67 | } 68 | } 69 | 70 | impl AddAssign for HashmapArena { 71 | fn add_assign(&mut self, rhs: Self) { 72 | self.buckets.extend(rhs.buckets) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /rsx-arena/src/hashmap/bucket.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use fnv::FnvHashMap; 13 | 14 | use types::{ArenaItemId, BucketId, EntryId}; 15 | use util::as_mut; 16 | 17 | #[derive(Debug)] 18 | pub struct HashmapBucket { 19 | bucket_id: BucketId, 20 | next_entry_id: EntryId, 21 | map: FnvHashMap, T> 22 | } 23 | 24 | impl PartialEq for HashmapBucket { 25 | fn eq(&self, other: &Self) -> bool { 26 | self.bucket_id == other.bucket_id 27 | } 28 | } 29 | 30 | impl Default for HashmapBucket { 31 | fn default() -> Self { 32 | HashmapBucket { 33 | bucket_id: BucketId::generate(), 34 | next_entry_id: EntryId::new(0), 35 | map: FnvHashMap::default() 36 | } 37 | } 38 | } 39 | 40 | impl HashmapBucket { 41 | pub fn new() -> Self { 42 | HashmapBucket::default() 43 | } 44 | 45 | pub fn owns(&self, id: ArenaItemId) -> bool { 46 | self.bucket_id == id.bucket_id 47 | } 48 | 49 | pub fn alloc(&mut self, value: T) -> ArenaItemId { 50 | let item_id = ArenaItemId { 51 | bucket_id: self.bucket_id, 52 | entry_id: self.next_entry_id.generate() 53 | }; 54 | self.map.insert(item_id, value); 55 | item_id 56 | } 57 | 58 | pub fn dealloc(&mut self, id: ArenaItemId) -> Option { 59 | debug_assert_eq!(self.bucket_id, id.bucket_id); 60 | self.map.remove(&id) 61 | } 62 | 63 | #[inline] 64 | pub fn get(&self, id: ArenaItemId) -> Option<&T> { 65 | debug_assert_eq!(self.bucket_id, id.bucket_id); 66 | self.map.get(&id) 67 | } 68 | 69 | #[inline] 70 | pub fn get_mut(&mut self, id: ArenaItemId) -> Option<&mut T> { 71 | debug_assert_eq!(self.bucket_id, id.bucket_id); 72 | self.map.get_mut(&id) 73 | } 74 | 75 | #[inline] 76 | pub unsafe fn get_as_mut<'a>(&mut self, id: ArenaItemId) -> Option<&'a mut T> { 77 | as_mut(self.get_mut(id)) 78 | } 79 | 80 | #[inline] 81 | pub fn get_mut_pair(&mut self, first_id: ArenaItemId, second_id: ArenaItemId) -> (Option<&mut T>, Option<&mut T>) { 82 | assert_ne!(first_id, second_id); 83 | let first = unsafe { self.get_as_mut(first_id) }; 84 | let second = unsafe { self.get_as_mut(second_id) }; 85 | (first, second) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /rsx-arena/src/hashmap/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | mod arena; 13 | mod bucket; 14 | 15 | pub use self::arena::*; 16 | pub use self::bucket::*; 17 | -------------------------------------------------------------------------------- /rsx-arena/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | extern crate fnv; 13 | extern crate num_traits; 14 | extern crate smallvec; 15 | 16 | mod util; 17 | mod common; 18 | mod hashmap; 19 | mod vec; 20 | 21 | pub mod types { 22 | pub use common::*; 23 | pub use hashmap::*; 24 | pub use vec::*; 25 | } 26 | -------------------------------------------------------------------------------- /rsx-arena/src/util.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | #[inline] 13 | pub unsafe fn as_mut<'a, V>(value: Option<&mut V>) -> Option<&'a mut V> { 14 | value.map(|v| v as *mut V).map(|v| &mut *v) 15 | } 16 | -------------------------------------------------------------------------------- /rsx-arena/src/vec/arena.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::ops::AddAssign; 13 | 14 | use types::{ArenaItemId, BucketId, EntryId}; 15 | use util::as_mut; 16 | 17 | #[derive(Debug)] 18 | pub struct VecArena { 19 | bucket_id: BucketId, 20 | vec: Vec 21 | } 22 | 23 | impl PartialEq for VecArena { 24 | fn eq(&self, other: &Self) -> bool { 25 | self.bucket_id == other.bucket_id 26 | } 27 | } 28 | 29 | impl Default for VecArena { 30 | fn default() -> Self { 31 | VecArena { 32 | bucket_id: BucketId::generate(), 33 | vec: Vec::with_capacity(1024) 34 | } 35 | } 36 | } 37 | 38 | impl VecArena { 39 | pub fn new() -> Self { 40 | VecArena::default() 41 | } 42 | 43 | pub fn owns(&self, id: ArenaItemId) -> bool { 44 | self.bucket_id == id.bucket_id 45 | } 46 | 47 | pub fn alloc(&mut self, value: T) -> ArenaItemId { 48 | let item_id = ArenaItemId { 49 | bucket_id: self.bucket_id, 50 | entry_id: EntryId::new(self.vec.len() as u32) 51 | }; 52 | self.vec.push(value); 53 | item_id 54 | } 55 | 56 | pub fn dealloc(&mut self, _: ArenaItemId) -> Option { 57 | unimplemented!() 58 | } 59 | 60 | #[inline] 61 | pub fn get(&self, id: ArenaItemId) -> Option<&T> { 62 | debug_assert_eq!(self.bucket_id, id.bucket_id); 63 | Some(unsafe { self.vec.get_unchecked(id.entry_id.to_index()) }) 64 | } 65 | 66 | #[inline] 67 | pub fn get_mut(&mut self, id: ArenaItemId) -> Option<&mut T> { 68 | debug_assert_eq!(self.bucket_id, id.bucket_id); 69 | Some(unsafe { self.vec.get_unchecked_mut(id.entry_id.to_index()) }) 70 | } 71 | 72 | #[inline] 73 | pub unsafe fn get_as_mut<'a>(&mut self, id: ArenaItemId) -> Option<&'a mut T> { 74 | as_mut(self.get_mut(id)) 75 | } 76 | 77 | #[inline] 78 | pub fn get_mut_pair(&mut self, first_id: ArenaItemId, second_id: ArenaItemId) -> (Option<&mut T>, Option<&mut T>) { 79 | assert_ne!(first_id, second_id); 80 | let first = unsafe { self.get_as_mut(first_id) }; 81 | let second = unsafe { self.get_as_mut(second_id) }; 82 | (first, second) 83 | } 84 | } 85 | 86 | impl AddAssign for VecArena { 87 | fn add_assign(&mut self, _: Self) { 88 | panic!("Extending vec-based arenas is not supported."); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /rsx-arena/src/vec/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | mod arena; 13 | 14 | pub use self::arena::*; 15 | -------------------------------------------------------------------------------- /rsx-dom/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsx-dom" 3 | version = "0.1.0" 4 | authors = ["Victor Porof "] 5 | 6 | [lib] 7 | name = "rsx_dom" 8 | 9 | [features] 10 | default = ["rsx-parse", "vec-arena"] 11 | rsx-parse = ["rsx-parser"] 12 | vec-arena = ["rsx-tree/vec-arena"] 13 | hashmap-arena = ["rsx-tree/hashmap-arena"] 14 | 15 | [dependencies] 16 | fnv = "1.0.6" 17 | rsx-shared = { git = "https://github.com/victorporof/rsx-shared.git", default-features = false } 18 | rsx-tree = { path = "../rsx-tree", default-features = false } 19 | serde = { version = "1.0.27", features = ["rc"] } 20 | serde_derive = "1.0.27" 21 | 22 | # Optional 23 | rsx-parser = { git = "https://github.com/victorporof/rsx-parser.git", default-features = false, optional = true } 24 | 25 | [dev-dependencies] 26 | rsx-shared = { git = "https://github.com/victorporof/rsx-shared.git", default-features = false, features = ["impl-dummy"] } 27 | quote = "0.3.15" 28 | syn = { version = "0.11.11", features = ["full"] } 29 | -------------------------------------------------------------------------------- /rsx-dom/src/convert.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::borrow::Cow; 13 | use std::rc::Rc; 14 | 15 | use rsx_shared::traits::{TComputedStyles, TGenericEvent, TLayoutNode, TStyleDeclarations}; 16 | 17 | use types::{ 18 | Closure, 19 | DOMAttribute, 20 | DOMAttributeName, 21 | DOMAttributeValue, 22 | DOMAttributes, 23 | DOMData, 24 | DOMNode, 25 | DOMNormalNode, 26 | DOMTagName, 27 | DOMText, 28 | DOMTextNode, 29 | DOMTree, 30 | EventType, 31 | KnownAttributeName, 32 | KnownElementName, 33 | Prop 34 | }; 35 | 36 | impl From<()> for DOMNode 37 | where 38 | E: TGenericEvent, 39 | S: TStyleDeclarations, 40 | C: TComputedStyles, 41 | L: TLayoutNode 42 | { 43 | fn from(_: ()) -> Self { 44 | DOMNode::new(DOMData::Void) 45 | } 46 | } 47 | 48 | impl From<&'static str> for DOMNode 49 | where 50 | E: TGenericEvent, 51 | S: TStyleDeclarations, 52 | C: TComputedStyles, 53 | L: TLayoutNode 54 | { 55 | fn from(text: &'static str) -> Self { 56 | DOMNode::new(DOMData::Text(DOMTextNode { 57 | content: DOMText::from(text) 58 | })) 59 | } 60 | } 61 | 62 | impl From for DOMNode 63 | where 64 | E: TGenericEvent, 65 | S: TStyleDeclarations, 66 | C: TComputedStyles, 67 | L: TLayoutNode 68 | { 69 | fn from(text: String) -> Self { 70 | DOMNode::new(DOMData::Text(DOMTextNode { 71 | content: DOMText::from(text) 72 | })) 73 | } 74 | } 75 | 76 | impl_text_node_from_stringifiable!(bool); 77 | impl_text_node_from_stringifiable!(i8); 78 | impl_text_node_from_stringifiable!(u8); 79 | impl_text_node_from_stringifiable!(i16); 80 | impl_text_node_from_stringifiable!(u16); 81 | impl_text_node_from_stringifiable!(i32); 82 | impl_text_node_from_stringifiable!(u32); 83 | impl_text_node_from_stringifiable!(i64); 84 | impl_text_node_from_stringifiable!(u64); 85 | impl_text_node_from_stringifiable!(f32); 86 | impl_text_node_from_stringifiable!(f64); 87 | impl_text_node_from_stringifiable!(isize); 88 | impl_text_node_from_stringifiable!(usize); 89 | impl_text_node_from_stringifiable!(char); 90 | 91 | impl From for DOMNode 92 | where 93 | E: TGenericEvent, 94 | S: TStyleDeclarations, 95 | C: TComputedStyles, 96 | L: TLayoutNode 97 | { 98 | fn from(tag: DOMTagName) -> Self { 99 | let attributes = vec![]; 100 | DOMNode::new(DOMData::Normal(DOMNormalNode { tag, attributes })) 101 | } 102 | } 103 | 104 | impl From<(DOMTagName, DOMAttributes)> for DOMNode 105 | where 106 | E: TGenericEvent, 107 | S: TStyleDeclarations, 108 | C: TComputedStyles, 109 | L: TLayoutNode 110 | { 111 | fn from((tag, attributes): (DOMTagName, DOMAttributes)) -> Self { 112 | DOMNode::new(DOMData::Normal(DOMNormalNode { tag, attributes })) 113 | } 114 | } 115 | 116 | impl From> for DOMNode 117 | where 118 | E: TGenericEvent, 119 | S: TStyleDeclarations, 120 | C: TComputedStyles, 121 | L: TLayoutNode 122 | { 123 | fn from(tree: DOMTree) -> Self { 124 | DOMNode::new(DOMData::ShadowHost(tree)) 125 | } 126 | } 127 | 128 | impl From<&'static str> for DOMText { 129 | fn from(value: &'static str) -> Self { 130 | DOMText::Static(Cow::from(value)) 131 | } 132 | } 133 | 134 | impl From for DOMText { 135 | fn from(value: String) -> Self { 136 | DOMText::Owned(Rc::new(value)) 137 | } 138 | } 139 | 140 | impl From for DOMTagName { 141 | fn from(name: KnownElementName) -> Self { 142 | DOMTagName::KnownName(name) 143 | } 144 | } 145 | 146 | impl From<&'static str> for DOMTagName { 147 | fn from(name: &'static str) -> Self { 148 | DOMTagName::Simple(name) 149 | } 150 | } 151 | 152 | impl From<(&'static str, &'static str)> for DOMTagName { 153 | fn from((namespace, name): (&'static str, &'static str)) -> Self { 154 | DOMTagName::NamedspacedName(namespace, name) 155 | } 156 | } 157 | 158 | impl From<(DOMAttributeName, DOMAttributeValue)> for DOMAttribute { 159 | fn from((name, value): (DOMAttributeName, DOMAttributeValue)) -> Self { 160 | DOMAttribute(name, value) 161 | } 162 | } 163 | 164 | impl From for DOMAttributeName { 165 | fn from(name: KnownAttributeName) -> Self { 166 | DOMAttributeName::KnownName(name) 167 | } 168 | } 169 | 170 | impl From for DOMAttributeName { 171 | fn from(name: EventType) -> Self { 172 | DOMAttributeName::EventType(name) 173 | } 174 | } 175 | 176 | impl From<&'static str> for DOMAttributeName { 177 | fn from(name: &'static str) -> Self { 178 | DOMAttributeName::Simple(name) 179 | } 180 | } 181 | 182 | impl From<(&'static str, &'static str)> for DOMAttributeName { 183 | fn from((namespace, name): (&'static str, &'static str)) -> Self { 184 | DOMAttributeName::NamedspacedName(namespace, name) 185 | } 186 | } 187 | 188 | impl From for DOMAttributeValue { 189 | fn from(value: bool) -> Self { 190 | DOMAttributeValue::Boolean(value) 191 | } 192 | } 193 | 194 | impl From for DOMAttributeValue { 195 | fn from(value: f64) -> Self { 196 | DOMAttributeValue::Number(value) 197 | } 198 | } 199 | 200 | impl_number_attribute_from_countable!(i8); 201 | impl_number_attribute_from_countable!(u8); 202 | impl_number_attribute_from_countable!(i16); 203 | impl_number_attribute_from_countable!(u16); 204 | impl_number_attribute_from_countable!(i32); 205 | impl_number_attribute_from_countable!(u32); 206 | impl_number_attribute_from_countable!(i64); 207 | impl_number_attribute_from_countable!(u64); 208 | impl_number_attribute_from_countable!(f32); 209 | impl_number_attribute_from_countable!(isize); 210 | impl_number_attribute_from_countable!(usize); 211 | 212 | impl From for DOMAttributeValue { 213 | fn from(value: char) -> Self { 214 | DOMAttributeValue::Char(value) 215 | } 216 | } 217 | 218 | impl From<&'static str> for DOMAttributeValue { 219 | fn from(value: &'static str) -> Self { 220 | DOMAttributeValue::Str(DOMText::from(value)) 221 | } 222 | } 223 | 224 | impl From for DOMAttributeValue { 225 | fn from(value: String) -> Self { 226 | DOMAttributeValue::Str(DOMText::from(value)) 227 | } 228 | } 229 | 230 | impl From for DOMAttributeValue { 231 | fn from(value: DOMText) -> Self { 232 | DOMAttributeValue::Str(value) 233 | } 234 | } 235 | 236 | impl From for DOMAttributeValue 237 | where 238 | E: TGenericEvent, 239 | S: TStyleDeclarations, 240 | C: TComputedStyles, 241 | L: TLayoutNode 242 | { 243 | fn from(value: S) -> Self { 244 | DOMAttributeValue::Styles(value) 245 | } 246 | } 247 | 248 | impl From for DOMAttributeValue { 249 | fn from(value: Prop) -> Self { 250 | DOMAttributeValue::Prop(value) 251 | } 252 | } 253 | 254 | impl From> for DOMAttributeValue { 255 | fn from(value: Closure) -> Self { 256 | DOMAttributeValue::EventListener(value) 257 | } 258 | } 259 | 260 | impl From> for DOMAttributeValue { 261 | fn from(value: DOMNode) -> Self { 262 | DOMAttributeValue::Node(value) 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /rsx-dom/src/export.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::convert::TryInto; 13 | 14 | use rsx_shared::traits::{TComputedStyles, TGenericEvent, TLayoutNode, TStyleDeclarations}; 15 | 16 | use types::{DOMData, DOMTagName, KnownElementName}; 17 | 18 | impl<'a, E, S, C, L> TryInto for &'a DOMData 19 | where 20 | E: TGenericEvent, 21 | S: TStyleDeclarations, 22 | C: TComputedStyles, 23 | L: TLayoutNode 24 | { 25 | type Error = (); 26 | 27 | fn try_into(self) -> Result { 28 | if let Some(&DOMTagName::KnownName(name)) = self.tag() { 29 | Ok(name) 30 | } else { 31 | Err(()) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rsx-dom/src/graph/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | mod node_id; 13 | mod node_ref; 14 | mod node_ref_mut; 15 | mod node_ref_mut_pair; 16 | mod tree; 17 | 18 | pub use self::node_id::*; 19 | pub use self::node_ref::*; 20 | pub use self::node_ref_mut::*; 21 | pub use self::node_ref_mut_pair::*; 22 | pub use self::tree::*; 23 | -------------------------------------------------------------------------------- /rsx-dom/src/graph/node_id.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use rsx_tree::types::Id; 13 | 14 | use types::DOMNode; 15 | 16 | pub type DOMNodeId = Id>; 17 | pub type DOMNodeIdPair = (DOMNodeId, DOMNodeId); 18 | 19 | pub type DOMNodeSiblingIds = (Option>, Option>); 20 | pub type DOMNodeEdgeIds = (Option>, Option>); 21 | -------------------------------------------------------------------------------- /rsx-dom/src/graph/node_ref.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::ops::Deref; 13 | 14 | use rsx_tree::types::Ref; 15 | 16 | use types::{DOMNode, DOMNodeEdgeIds, DOMNodeId, DOMNodeSiblingIds}; 17 | 18 | #[derive(Debug, PartialEq)] 19 | pub struct DOMArenaRef<'a, E: 'a, S: 'a, C: 'a, L: 'a> { 20 | raw: Ref<'a, DOMNode> 21 | } 22 | 23 | impl<'a, E, S, C, L> From>> for DOMArenaRef<'a, E, S, C, L> { 24 | fn from(raw: Ref<'a, DOMNode>) -> Self { 25 | DOMArenaRef { raw } 26 | } 27 | } 28 | 29 | impl<'a, E, S, C, L> Deref for DOMArenaRef<'a, E, S, C, L> { 30 | type Target = DOMNode; 31 | 32 | fn deref(&self) -> &Self::Target { 33 | self.value() 34 | } 35 | } 36 | 37 | impl<'a, E, S, C, L> DOMArenaRef<'a, E, S, C, L> { 38 | pub(crate) fn value(&self) -> &'a DOMNode { 39 | self.raw.try_value().expect("Node deallocated") 40 | } 41 | 42 | pub(crate) fn into_value(self) -> &'a DOMNode { 43 | self.raw.try_into_value().expect("Node deallocated") 44 | } 45 | 46 | pub fn get(&self, id: DOMNodeId) -> DOMArenaRef<'a, E, S, C, L> { 47 | DOMArenaRef::from(self.raw.tree().get(id)) 48 | } 49 | 50 | pub fn id(&self) -> DOMNodeId { 51 | self.raw.id() 52 | } 53 | 54 | pub fn parent_id(&self) -> Option> { 55 | self.raw.parent_id() 56 | } 57 | 58 | pub fn parent(&self) -> Option> { 59 | self.raw.parent().map(DOMArenaRef::from) 60 | } 61 | 62 | pub fn prev_sibling_id(&self) -> Option> { 63 | self.raw.prev_sibling_id() 64 | } 65 | 66 | pub fn prev_sibling(&self) -> Option> { 67 | self.raw.prev_sibling().map(DOMArenaRef::from) 68 | } 69 | 70 | pub fn next_sibling_id(&self) -> Option> { 71 | self.raw.next_sibling_id() 72 | } 73 | 74 | pub fn next_sibling(&self) -> Option> { 75 | self.raw.next_sibling().map(DOMArenaRef::from) 76 | } 77 | 78 | pub fn first_child_id(&self) -> Option> { 79 | self.raw.first_child_id() 80 | } 81 | 82 | pub fn first_child(&self) -> Option> { 83 | self.raw.first_child().map(DOMArenaRef::from) 84 | } 85 | 86 | pub fn last_child_id(&self) -> Option> { 87 | self.raw.last_child_id() 88 | } 89 | 90 | pub fn last_child(&self) -> Option> { 91 | self.raw.last_child().map(DOMArenaRef::from) 92 | } 93 | 94 | pub fn sibling_ids(&self) -> DOMNodeSiblingIds { 95 | self.raw.sibling_ids() 96 | } 97 | 98 | pub fn edge_ids(&self) -> DOMNodeEdgeIds { 99 | self.raw.edge_ids() 100 | } 101 | 102 | pub fn children_iter(&self) -> impl Iterator> { 103 | self.raw.children_values_iter() 104 | } 105 | 106 | pub fn descendants_iter(&self) -> impl Iterator> { 107 | self.raw.descendants_values_iter() 108 | } 109 | 110 | pub fn traverse_iter(&self) -> impl Iterator> { 111 | self.raw.traverse_values_iter() 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /rsx-dom/src/graph/node_ref_mut.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::ops::{Deref, DerefMut}; 13 | 14 | use rsx_shared::traits::{TComputedStyles, TDOMNode, TGenericEvent, TLayoutNode, TStyleDeclarations}; 15 | use rsx_tree::types::{Ref, RefMut}; 16 | 17 | use types::{DOMArenaRef, DOMArenaRefMutPair, DOMNode, DOMNodeEdgeIds, DOMNodeId, DOMNodeIdPair, DOMNodeSiblingIds, DOMTree}; 18 | 19 | #[derive(Debug, PartialEq)] 20 | pub struct DOMArenaRefMut<'a, E: 'a, S: 'a, C: 'a, L: 'a> { 21 | raw: RefMut<'a, DOMNode> 22 | } 23 | 24 | impl<'a, E, S, C, L> From>> for DOMArenaRefMut<'a, E, S, C, L> { 25 | fn from(raw: RefMut<'a, DOMNode>) -> Self { 26 | DOMArenaRefMut { raw } 27 | } 28 | } 29 | 30 | impl<'a, E, S, C, L> Into> for DOMArenaRefMut<'a, E, S, C, L> { 31 | fn into(self) -> DOMArenaRef<'a, E, S, C, L> { 32 | DOMArenaRef::from(Into::>>::into(self.raw)) 33 | } 34 | } 35 | 36 | impl<'a, E, S, C, L> Deref for DOMArenaRefMut<'a, E, S, C, L> { 37 | type Target = DOMNode; 38 | 39 | fn deref(&self) -> &Self::Target { 40 | self.value() 41 | } 42 | } 43 | 44 | impl<'a, E, S, C, L> DerefMut for DOMArenaRefMut<'a, E, S, C, L> { 45 | fn deref_mut(&mut self) -> &mut Self::Target { 46 | self.value_mut() 47 | } 48 | } 49 | 50 | impl<'a, E, S, C, L> DOMArenaRefMut<'a, E, S, C, L> { 51 | pub(crate) fn value(&self) -> &DOMNode { 52 | self.raw.try_value().expect("Node deallocated") 53 | } 54 | 55 | pub(crate) fn value_mut(&mut self) -> &mut DOMNode { 56 | self.raw.try_value_mut().expect("Node deallocated") 57 | } 58 | 59 | pub(crate) fn into_value(self) -> &'a mut DOMNode { 60 | self.raw.try_into_value().expect("Node deallocated") 61 | } 62 | 63 | pub fn get(&mut self, id: DOMNodeId) -> DOMArenaRef { 64 | DOMArenaRef::from(self.raw.tree().get(id)) 65 | } 66 | 67 | pub fn get_mut(&mut self, id: DOMNodeId) -> DOMArenaRefMut { 68 | DOMArenaRefMut::from(self.raw.tree_mut().get_mut(id)) 69 | } 70 | 71 | pub fn get_mut_pair(&mut self, ids: DOMNodeIdPair) -> DOMArenaRefMutPair { 72 | DOMArenaRefMutPair::from(self.raw.tree_mut().get_mut_pair(ids)) 73 | } 74 | 75 | pub fn get_mut_self_and(&mut self, id: DOMNodeId) -> DOMArenaRefMutPair { 76 | let ids = (self.id(), id); 77 | DOMArenaRefMutPair::from(self.raw.tree_mut().get_mut_pair(ids)) 78 | } 79 | 80 | pub fn id(&self) -> DOMNodeId { 81 | self.raw.id() 82 | } 83 | 84 | pub fn parent_id(&self) -> Option> { 85 | self.raw.parent_id() 86 | } 87 | 88 | pub fn parent(&mut self) -> Option> { 89 | self.raw.parent().map(DOMArenaRefMut::from) 90 | } 91 | 92 | pub fn prev_sibling_id(&self) -> Option> { 93 | self.raw.prev_sibling_id() 94 | } 95 | 96 | pub fn prev_sibling(&mut self) -> Option> { 97 | self.raw.prev_sibling().map(DOMArenaRefMut::from) 98 | } 99 | 100 | pub fn next_sibling_id(&self) -> Option> { 101 | self.raw.next_sibling_id() 102 | } 103 | 104 | pub fn next_sibling(&mut self) -> Option> { 105 | self.raw.next_sibling().map(DOMArenaRefMut::from) 106 | } 107 | 108 | pub fn first_child_id(&self) -> Option> { 109 | self.raw.first_child_id() 110 | } 111 | 112 | pub fn first_child(&mut self) -> Option> { 113 | self.raw.first_child().map(DOMArenaRefMut::from) 114 | } 115 | 116 | pub fn last_child_id(&self) -> Option> { 117 | self.raw.last_child_id() 118 | } 119 | 120 | pub fn last_child(&mut self) -> Option> { 121 | self.raw.last_child().map(DOMArenaRefMut::from) 122 | } 123 | 124 | pub fn sibling_ids(&self) -> DOMNodeSiblingIds { 125 | self.raw.sibling_ids() 126 | } 127 | 128 | pub fn edge_ids(&self) -> DOMNodeEdgeIds { 129 | self.raw.edge_ids() 130 | } 131 | 132 | pub fn append_tree(&mut self, other: DOMTree) -> bool { 133 | self.raw.append_tree(other.into_inner()) 134 | } 135 | 136 | pub fn prepend_tree(&mut self, other: DOMTree) -> bool { 137 | self.raw.prepend_tree(other.into_inner()) 138 | } 139 | 140 | pub fn append(&mut self, node: DOMNode) -> DOMArenaRefMut { 141 | DOMArenaRefMut::from(self.raw.append(node)) 142 | } 143 | 144 | pub fn prepend(&mut self, node: DOMNode) -> DOMArenaRefMut { 145 | DOMArenaRefMut::from(self.raw.prepend(node)) 146 | } 147 | 148 | pub fn detach(&mut self) { 149 | self.raw.detach(); 150 | } 151 | } 152 | 153 | impl<'a, E, S, C, L> DOMArenaRefMut<'a, E, S, C, L> 154 | where 155 | E: TGenericEvent, 156 | S: TStyleDeclarations, 157 | C: TComputedStyles, 158 | L: TLayoutNode 159 | { 160 | pub fn append_with_layout(&mut self, child_id: DOMNodeId, resources: &L::Resources) -> Result<(), ()> 161 | where 162 | L: TLayoutNode 163 | { 164 | debug_assert_eq!(self.get(child_id).parent_id(), None); 165 | 166 | self.raw.append_id(child_id); 167 | 168 | let (this_node, child_node) = self.get_mut_self_and(child_id).into_values(); 169 | child_node.apply_measurement_metadata_to_layout(resources, &this_node.computed_styles); 170 | child_node.append_to_layout_node(this_node); 171 | 172 | Ok(()) 173 | } 174 | 175 | pub fn remove_with_layout(&mut self, child_id: DOMNodeId) -> Result<(), ()> { 176 | debug_assert_eq!(self.get(child_id).parent_id(), Some(self.id())); 177 | 178 | self.raw.tree_mut().get_mut(child_id).detach(); 179 | 180 | let (this_node, child_node) = self.get_mut_self_and(child_id).into_values(); 181 | child_node.remove_from_layout_node(this_node); 182 | 183 | Ok(()) 184 | } 185 | 186 | pub fn build_layout(&mut self, resources: &L::Resources) 187 | where 188 | L: TLayoutNode 189 | { 190 | debug_assert_eq!(self.layout_node().is_tainted(), false); 191 | 192 | let mut next_child_id = self.first_child_id(); 193 | while let Some(child_id) = next_child_id { 194 | { 195 | let mut child_ref = self.get_mut(child_id); 196 | child_ref.build_layout(resources); 197 | } 198 | { 199 | let (this_node, child_node) = self.get_mut_self_and(child_id).into_values(); 200 | child_node.apply_measurement_metadata_to_layout(resources, &this_node.computed_styles); 201 | child_node.append_to_layout_node(this_node); 202 | } 203 | next_child_id = self.get(child_id).next_sibling_id(); 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /rsx-dom/src/graph/node_ref_mut_pair.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use rsx_tree::types::RefMutPair; 13 | 14 | use types::DOMNode; 15 | 16 | #[derive(Debug, PartialEq)] 17 | pub struct DOMArenaRefMutPair<'a, E: 'a, S: 'a, C: 'a, L: 'a> { 18 | raw: RefMutPair<'a, DOMNode> 19 | } 20 | 21 | impl<'a, E, S, C, L> From>> for DOMArenaRefMutPair<'a, E, S, C, L> { 22 | fn from(raw: RefMutPair<'a, DOMNode>) -> Self { 23 | DOMArenaRefMutPair { raw } 24 | } 25 | } 26 | 27 | impl<'a, E, S, C, L> DOMArenaRefMutPair<'a, E, S, C, L> { 28 | #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))] 29 | pub fn values(&mut self) -> (&mut DOMNode, &mut DOMNode) { 30 | self.raw.try_values().expect("Nodes deallocated") 31 | } 32 | 33 | #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))] 34 | pub fn into_values(self) -> (&'a mut DOMNode, &'a mut DOMNode) { 35 | self.raw.try_into_values().expect("Nodes deallocated") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /rsx-dom/src/graph/tree.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::ops::{Deref, DerefMut}; 13 | 14 | use rsx_shared::traits::{TComputedStyles, TDOMTree, TGenericEvent, TLayoutNode, TStyleDeclarations}; 15 | use rsx_tree::types::Tree; 16 | 17 | use types::{DOMArenaRef, DOMArenaRefMut, DOMArenaRefMutPair, DOMNode, DOMNodeId, DOMNodeIdPair}; 18 | 19 | #[derive(Debug, PartialEq)] 20 | pub struct DOMTree { 21 | raw: Tree> 22 | } 23 | 24 | impl Default for DOMTree 25 | where 26 | E: TGenericEvent, 27 | S: TStyleDeclarations, 28 | C: TComputedStyles, 29 | L: TLayoutNode 30 | { 31 | fn default() -> Self { 32 | DOMTree { 33 | raw: Tree::new(DOMNode::default()) 34 | } 35 | } 36 | } 37 | 38 | impl Deref for DOMTree { 39 | type Target = DOMNode; 40 | 41 | fn deref(&self) -> &Self::Target { 42 | self.root().into_value() 43 | } 44 | } 45 | 46 | impl DerefMut for DOMTree { 47 | fn deref_mut(&mut self) -> &mut Self::Target { 48 | self.root_mut().into_value() 49 | } 50 | } 51 | 52 | impl DOMTree { 53 | pub(crate) fn into_inner(self) -> Tree> { 54 | self.raw 55 | } 56 | 57 | pub fn root(&self) -> DOMArenaRef { 58 | let id = self.raw.root(); 59 | DOMArenaRef::from(self.raw.get(id)) 60 | } 61 | 62 | pub fn root_mut(&mut self) -> DOMArenaRefMut { 63 | let id = self.raw.root(); 64 | DOMArenaRefMut::from(self.raw.get_mut(id)) 65 | } 66 | 67 | pub fn document(&self) -> DOMArenaRef { 68 | let id = self.root().first_child_id().unwrap(); 69 | DOMArenaRef::from(self.raw.get(id)) 70 | } 71 | 72 | pub fn document_mut(&mut self) -> DOMArenaRefMut { 73 | let id = self.root().first_child_id().unwrap(); 74 | DOMArenaRefMut::from(self.raw.get_mut(id)) 75 | } 76 | 77 | pub fn alloc(&mut self, node: DOMNode) -> DOMNodeId { 78 | self.raw.alloc(node) 79 | } 80 | 81 | pub fn get(&self, id: DOMNodeId) -> DOMArenaRef { 82 | DOMArenaRef::from(self.raw.get(id)) 83 | } 84 | 85 | pub fn get_mut(&mut self, id: DOMNodeId) -> DOMArenaRefMut { 86 | DOMArenaRefMut::from(self.raw.get_mut(id)) 87 | } 88 | 89 | pub fn get_mut_pair(&mut self, ids: DOMNodeIdPair) -> DOMArenaRefMutPair { 90 | DOMArenaRefMutPair::from(self.raw.get_mut_pair(ids)) 91 | } 92 | } 93 | 94 | impl TDOMTree for DOMTree 95 | where 96 | E: TGenericEvent, 97 | S: TStyleDeclarations, 98 | C: TComputedStyles, 99 | L: TLayoutNode 100 | { 101 | type Node = DOMNode; 102 | 103 | fn get_node(&self, id: DOMNodeId) -> &Self::Node { 104 | self.get(id).into_value() 105 | } 106 | 107 | fn get_node_mut(&mut self, id: DOMNodeId) -> &mut Self::Node { 108 | self.get_mut(id).into_value() 109 | } 110 | 111 | fn get_node_mut_pair(&mut self, ids: DOMNodeIdPair) -> (&mut Self::Node, &mut Self::Node) { 112 | self.get_mut_pair(ids).into_values() 113 | } 114 | } 115 | 116 | impl DOMTree 117 | where 118 | E: TGenericEvent, 119 | S: TStyleDeclarations, 120 | C: TComputedStyles, 121 | L: TLayoutNode 122 | { 123 | pub fn generate_layout_tree(&mut self, resources: &L::Resources) 124 | where 125 | L: TLayoutNode 126 | { 127 | self.root_mut().build_layout(resources); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /rsx-dom/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | #![cfg_attr(feature = "cargo-clippy", allow(match_ref_pats))] 13 | #![feature(conservative_impl_trait)] 14 | #![feature(never_type)] 15 | #![feature(try_from)] 16 | 17 | extern crate fnv; 18 | extern crate rsx_shared; 19 | extern crate rsx_tree; 20 | extern crate serde; 21 | #[macro_use] 22 | extern crate serde_derive; 23 | 24 | #[cfg(feature = "rsx-parse")] 25 | pub extern crate rsx_parser; 26 | 27 | #[macro_use] 28 | pub mod macros; 29 | 30 | mod graph; 31 | mod convert; 32 | mod export; 33 | 34 | pub mod types; 35 | pub mod util; 36 | -------------------------------------------------------------------------------- /rsx-dom/src/macros.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | #[macro_export] 13 | macro_rules! fragment { 14 | (@ $parent:ident; DOMNode::from 15 | (( 16 | $name:expr, 17 | vec![ 18 | $( $attributes:tt )* 19 | ], 20 | vec![ 21 | $( $children:tt )* 22 | ] 23 | )) 24 | $( $tail:tt )* 25 | ) => { 26 | { 27 | let mut parent = $parent.append(DOMNode::from(($name, vec![$( $attributes )*]))); 28 | fragment! { @ parent; $( $children )* } 29 | } 30 | fragment! { @ $parent; $( $tail )* } 31 | }; 32 | 33 | (@ $parent:ident; DOMNode::from 34 | (( 35 | $name:expr, 36 | DOMChildren::from(vec![ 37 | $( $children:tt )* 38 | ]) 39 | )) 40 | $( $tail:tt )* 41 | ) => { 42 | { 43 | let mut parent = $parent.append(DOMNode::from($name)); 44 | fragment! { @ parent; $( $children )* } 45 | } 46 | fragment! { @ $parent; $( $tail )* } 47 | }; 48 | 49 | (@ $parent:ident; DOMNode::from 50 | (( 51 | $name:expr, 52 | DOMAttributes:from(vec![ 53 | $( $attributes:tt )* 54 | ]) 55 | )) 56 | $( $tail:tt )* 57 | ) => { 58 | $parent.append(DOMNode::from(($name, vec![$( $attributes )*]))); 59 | fragment! { @ $parent; $( $tail )* } 60 | }; 61 | 62 | (@ $parent:ident; DOMNode::from 63 | ( 64 | $code:block 65 | ) 66 | $( $tail:tt )* 67 | ) => { 68 | { 69 | let node = DOMNode::from($code); 70 | if node.is_shadow_host() { 71 | $parent.append_tree(node.shadow_dom()); 72 | } else if !node.is_void() { 73 | $parent.append(node); 74 | } 75 | } 76 | fragment! { @ $parent; $( $tail )* } 77 | }; 78 | 79 | (@ $parent:ident; DOMNode::from 80 | ( 81 | $name:expr 82 | ) 83 | $( $tail:tt )* 84 | ) => { 85 | $parent.append(DOMNode::from($name)); 86 | fragment! { @ $parent; $( $tail )* } 87 | }; 88 | 89 | (@ $parent:ident; , $( $tail:tt )* ) => { 90 | fragment! { @ $parent; $( $tail )* } 91 | }; 92 | 93 | (@ $parent:ident; ) => {}; 94 | 95 | ($( $tt:tt )*) => {{ 96 | let mut fragment = DOMTree::default(); 97 | { 98 | let mut parent = fragment.root_mut(); 99 | fragment! { @ parent; $( $tt )* } 100 | } 101 | fragment 102 | }}; 103 | } 104 | 105 | macro_rules! impl_text_node_from_stringifiable { 106 | ($src: ty) => { 107 | impl From<$src> for DOMNode 108 | where 109 | E: TGenericEvent, 110 | S: TStyleDeclarations, 111 | C: TComputedStyles, 112 | L: TLayoutNode 113 | { 114 | fn from(value: $src) -> Self { 115 | DOMNode::new(DOMData::Text(DOMTextNode { 116 | content: DOMText::from(value.to_string()) 117 | })) 118 | } 119 | } 120 | }; 121 | } 122 | 123 | macro_rules! impl_number_attribute_from_countable { 124 | ($src: ty) => { 125 | impl From<$src> for DOMAttributeValue { 126 | #[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] 127 | fn from(value: $src) -> Self { 128 | DOMAttributeValue::Number(value as f64) 129 | } 130 | } 131 | }; 132 | } 133 | -------------------------------------------------------------------------------- /rsx-dom/src/types.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use std::borrow::{Borrow, Cow}; 13 | use std::cmp::Ordering; 14 | use std::rc::Rc; 15 | 16 | use rsx_shared::traits::{TComputedStyles, TDOMNode, TDOMText, TGenericEvent, TLayoutNode, TStyleDeclarations}; 17 | 18 | #[cfg(feature = "rsx-parse")] 19 | pub use rsx_parser::types::*; 20 | pub use rsx_shared::types::{Closure, EventType, KnownAttributeName, KnownElementName, Prop}; 21 | 22 | use util::{find_src, is_event_listener, is_style}; 23 | 24 | pub use graph::*; 25 | 26 | pub type DOMAttributes = Vec>; 27 | pub type DOMChildren = Vec>; 28 | 29 | #[derive(Debug, PartialEq)] 30 | pub struct DOMNode { 31 | pub(crate) data: DOMData, 32 | pub(crate) computed_styles: C, 33 | pub(crate) layout_node: L 34 | } 35 | 36 | impl Default for DOMNode 37 | where 38 | E: TGenericEvent, 39 | S: TStyleDeclarations, 40 | C: TComputedStyles, 41 | L: TLayoutNode 42 | { 43 | fn default() -> Self { 44 | DOMNode::from(DOMTagName::from(KnownElementName::Fragment)) 45 | } 46 | } 47 | 48 | impl DOMNode 49 | where 50 | E: TGenericEvent, 51 | S: TStyleDeclarations, 52 | C: TComputedStyles, 53 | L: TLayoutNode 54 | { 55 | pub fn new(data: DOMData) -> Self { 56 | let user_agent_styles = S::make_user_agent_styles(&data); 57 | 58 | let mut computed_styles = C::make_initial_computed_styles(&data); 59 | computed_styles.apply_styles(&user_agent_styles); 60 | computed_styles.apply_rules(data.get_styles()); 61 | 62 | let mut layout_node = L::make_initial_layout_node(&data); 63 | layout_node.apply_styles(&user_agent_styles); 64 | layout_node.apply_rules(data.get_styles()); 65 | 66 | DOMNode { 67 | computed_styles, 68 | layout_node, 69 | data 70 | } 71 | } 72 | 73 | pub fn shadow_dom(self) -> DOMTree { 74 | match self.data { 75 | DOMData::ShadowHost(tree) => tree, 76 | DOMData::Void | DOMData::Text(_) | DOMData::Normal(_) => DOMTree::default() 77 | } 78 | } 79 | } 80 | 81 | impl TDOMNode for DOMNode 82 | where 83 | E: TGenericEvent, 84 | S: TStyleDeclarations, 85 | C: TComputedStyles, 86 | L: TLayoutNode 87 | { 88 | type Id = DOMNodeId; 89 | type Data = DOMData; 90 | type Event = E; 91 | type Styles = S; 92 | type ComputedStyles = C; 93 | type LayoutNode = L; 94 | 95 | fn data(&self) -> &DOMData { 96 | &self.data 97 | } 98 | 99 | fn is_void(&self) -> bool { 100 | self.data.is_void() 101 | } 102 | 103 | fn is_shadow_host(&self) -> bool { 104 | self.data.is_shadow_host().is_some() 105 | } 106 | 107 | fn is_text(&self) -> bool { 108 | self.data.is_text().is_some() 109 | } 110 | 111 | fn is_normal(&self) -> bool { 112 | self.data.is_normal().is_some() 113 | } 114 | 115 | fn is_known(&self, name: KnownElementName) -> bool { 116 | self.data.is_known(name).is_some() 117 | } 118 | 119 | fn computed_styles(&self) -> &C { 120 | &self.computed_styles 121 | } 122 | 123 | fn layout_node(&self) -> &L { 124 | &self.layout_node 125 | } 126 | 127 | fn reflow_subtree(&mut self, width: u32, height: u32, direction: L::ReflowDirection) { 128 | self.layout_node.reflow_subtree(width, height, direction); 129 | } 130 | 131 | fn set_computed_client_position(&mut self, computed: L::ClientPosition) { 132 | self.layout_node.set_computed_client_position(computed) 133 | } 134 | 135 | fn get_local_bounding_client_rect(&self) -> L::BoundingClientRect { 136 | self.layout_node.get_local_bounding_client_rect() 137 | } 138 | 139 | fn get_global_bounding_client_rect(&self) -> L::BoundingClientRect { 140 | self.layout_node.get_global_bounding_client_rect() 141 | } 142 | 143 | fn get_measured_image(&self) -> &L::MeasuredImage { 144 | self.layout_node.get_measured_image() 145 | } 146 | 147 | fn get_shaped_text(&self) -> &L::ShapedText { 148 | self.layout_node.get_shaped_text() 149 | } 150 | } 151 | 152 | impl DOMNode 153 | where 154 | E: TGenericEvent, 155 | S: TStyleDeclarations, 156 | C: TComputedStyles, 157 | L: TLayoutNode 158 | { 159 | pub fn set_text_content(&mut self, text: String, resources: &L::Resources) 160 | where 161 | L: TLayoutNode 162 | { 163 | let data = &mut self.data; 164 | let computed_styles = &self.computed_styles; 165 | let layout_node = &mut self.layout_node; 166 | 167 | let content = DOMText::from(text); 168 | layout_node.measure_self_as_text(resources, &content, computed_styles); 169 | *data = DOMData::Text(DOMTextNode { content }); 170 | } 171 | 172 | pub fn reset_styles(&mut self) -> Option<()> 173 | where 174 | C: TComputedStyles, 175 | L: TLayoutNode 176 | { 177 | self.data.drop_styles()?; 178 | 179 | let user_agent_styles = S::make_user_agent_styles(&self.data); 180 | 181 | self.computed_styles.reset_custom_styles(&self.data); 182 | self.computed_styles.apply_styles(&user_agent_styles); 183 | 184 | self.layout_node.reset_custom_styles(&self.data); 185 | self.layout_node.apply_styles(&user_agent_styles); 186 | 187 | Some(()) 188 | } 189 | 190 | pub fn apply_styles(&mut self, styles: S) -> Option<()> 191 | where 192 | C: TComputedStyles, 193 | L: TLayoutNode 194 | { 195 | self.data.attributes_mut()?.push(DOMAttribute::from(( 196 | DOMAttributeName::from(KnownAttributeName::Style), 197 | DOMAttributeValue::from(styles) 198 | ))); 199 | 200 | self.computed_styles.apply_rules(self.data.get_styles()); 201 | self.layout_node.apply_rules(self.data.get_styles()); 202 | 203 | // TODO: Update measurement metadata for the layout node if necessary. 204 | // E.g. if the font size changed the text measurement changes. 205 | 206 | Some(()) 207 | } 208 | 209 | pub(crate) fn apply_measurement_metadata_to_layout(&mut self, resources: &L::Resources, inherited_styles: &C) 210 | where 211 | L: TLayoutNode 212 | { 213 | use self::KnownElementName::*; 214 | 215 | let data = &self.data; 216 | let computed_styles = &mut self.computed_styles; 217 | let layout_node = &mut self.layout_node; 218 | 219 | if let Some(text) = data.text() { 220 | computed_styles.inherit_styles(inherited_styles); 221 | layout_node.measure_self_as_text(resources, text, computed_styles); 222 | } else if let Some(src) = data.is_known(Image).and(find_src(data.get_attributes())) { 223 | layout_node.measure_self_as_image(resources, src, &()); 224 | } 225 | } 226 | 227 | pub(crate) fn append_to_layout_node(&mut self, parent: &mut DOMNode) { 228 | let parent = &mut parent.layout_node; 229 | let child = &mut self.layout_node; 230 | parent.append_child(child); 231 | } 232 | 233 | pub(crate) fn remove_from_layout_node(&mut self, parent: &mut DOMNode) { 234 | let parent = &mut parent.layout_node; 235 | let child = &mut self.layout_node; 236 | parent.remove_child(child); 237 | } 238 | } 239 | 240 | #[derive(Debug, Eq, Ord, Clone, Serialize, Deserialize)] 241 | pub enum DOMText { 242 | Static(Cow<'static, str>), 243 | Owned(Rc) 244 | } 245 | 246 | impl TDOMText for DOMText {} 247 | 248 | impl PartialEq for DOMText { 249 | fn eq(&self, other: &Self) -> bool { 250 | self.as_ref() == other.as_ref() 251 | } 252 | } 253 | 254 | impl PartialOrd for DOMText { 255 | fn partial_cmp(&self, other: &Self) -> Option { 256 | self.as_ref().partial_cmp(other.as_ref()) 257 | } 258 | } 259 | 260 | impl Borrow for DOMText { 261 | fn borrow(&self) -> &str { 262 | self.as_ref() 263 | } 264 | } 265 | 266 | impl AsRef for DOMText { 267 | fn as_ref(&self) -> &str { 268 | match self { 269 | &DOMText::Static(ref v) => v.as_ref(), 270 | &DOMText::Owned(ref v) => v.as_ref() 271 | } 272 | } 273 | } 274 | 275 | #[derive(Debug, PartialEq)] 276 | pub enum DOMData { 277 | Void, 278 | ShadowHost(DOMTree), 279 | Text(DOMTextNode), 280 | Normal(DOMNormalNode) 281 | } 282 | 283 | #[allow(dead_code)] 284 | impl DOMData { 285 | pub fn text(&self) -> Option<&DOMText> { 286 | match self { 287 | &DOMData::Text(DOMTextNode { ref content }) => Some(content), 288 | &DOMData::Void | &DOMData::ShadowHost(_) | &DOMData::Normal(_) => None 289 | } 290 | } 291 | 292 | pub fn tag(&self) -> Option<&DOMTagName> { 293 | match self { 294 | &DOMData::Void | &DOMData::ShadowHost(_) | &DOMData::Text(_) => None, 295 | &DOMData::Normal(DOMNormalNode { ref tag, .. }) => Some(tag) 296 | } 297 | } 298 | 299 | pub(crate) fn is_void(&self) -> bool { 300 | match self { 301 | &DOMData::Void => true, 302 | _ => false 303 | } 304 | } 305 | 306 | pub(crate) fn is_shadow_host(&self) -> Option<&DOMTree> { 307 | match self { 308 | &DOMData::ShadowHost(ref value) => Some(value), 309 | _ => None 310 | } 311 | } 312 | 313 | pub(crate) fn is_text(&self) -> Option<&DOMTextNode> { 314 | match self { 315 | &DOMData::Text(ref value) => Some(value), 316 | _ => None 317 | } 318 | } 319 | 320 | pub(crate) fn is_normal(&self) -> Option<&DOMNormalNode> { 321 | match self { 322 | &DOMData::Normal(ref value) => Some(value), 323 | _ => None 324 | } 325 | } 326 | 327 | pub(crate) fn is_known(&self, name: KnownElementName) -> Option<&DOMNormalNode> { 328 | match self { 329 | &DOMData::Normal(ref value) if value.tag == DOMTagName::KnownName(name) => Some(value), 330 | _ => None 331 | } 332 | } 333 | 334 | pub(crate) fn drop_event_listeners(&mut self) -> Option<&mut Vec>> { 335 | let attributes = self.attributes_mut()?; 336 | attributes.retain(|i| is_event_listener(i).is_none()); 337 | Some(attributes) 338 | } 339 | 340 | pub(crate) fn drop_styles(&mut self) -> Option<&mut Vec>> { 341 | let attributes = self.attributes_mut()?; 342 | attributes.retain(|i| is_style(i).is_none()); 343 | Some(attributes) 344 | } 345 | 346 | #[cfg_attr(rustfmt, rustfmt_skip)] 347 | pub(crate) fn attributes_ref(&self) -> Option<&Vec>> { 348 | match self { 349 | &DOMData::Void | &DOMData::ShadowHost(_) | &DOMData::Text(_) => None, 350 | &DOMData::Normal(DOMNormalNode { ref attributes, .. }) => Some(attributes) 351 | } 352 | } 353 | 354 | #[cfg_attr(rustfmt, rustfmt_skip)] 355 | pub(crate) fn attributes_mut(&mut self) -> Option<&mut Vec>> { 356 | match self { 357 | &mut DOMData::Void | &mut DOMData::ShadowHost(_) | &mut DOMData::Text(_) => None, 358 | &mut DOMData::Normal(DOMNormalNode { ref mut attributes, .. }) => Some(attributes) 359 | } 360 | } 361 | 362 | pub(crate) fn attributes_slice(&self) -> &[DOMAttribute] { 363 | self.attributes_ref().map(|v| &v[..]).unwrap_or(&[]) 364 | } 365 | 366 | pub(crate) fn attributes_slice_mut(&mut self) -> &mut [DOMAttribute] { 367 | self.attributes_mut().map(|v| &mut v[..]).unwrap_or(&mut []) 368 | } 369 | 370 | #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] 371 | pub fn get_attributes<'a>(&'a self) -> impl Iterator> { 372 | self.attributes_slice().iter() 373 | } 374 | 375 | #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] 376 | pub fn get_event_listeners<'a>(&'a self) -> impl Iterator> { 377 | self.attributes_slice().iter().filter_map(is_event_listener) 378 | } 379 | 380 | #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] 381 | pub fn get_styles<'a>(&'a self) -> impl Iterator { 382 | self.attributes_slice().iter().filter_map(is_style) 383 | } 384 | } 385 | 386 | #[derive(Debug, PartialEq)] 387 | pub struct DOMTextNode { 388 | pub(crate) content: DOMText 389 | } 390 | 391 | #[derive(Debug, PartialEq)] 392 | pub struct DOMNormalNode { 393 | pub(crate) tag: DOMTagName, 394 | pub(crate) attributes: DOMAttributes 395 | } 396 | 397 | #[derive(Debug, PartialEq)] 398 | pub enum DOMTagName { 399 | KnownName(KnownElementName), 400 | Simple(&'static str), 401 | NamedspacedName(&'static str, &'static str) 402 | } 403 | 404 | #[derive(Debug, PartialEq)] 405 | pub struct DOMAttribute(pub DOMAttributeName, pub DOMAttributeValue); 406 | 407 | #[derive(Debug, PartialEq)] 408 | pub enum DOMAttributeName { 409 | KnownName(KnownAttributeName), 410 | EventType(EventType), 411 | Simple(&'static str), 412 | NamedspacedName(&'static str, &'static str) 413 | } 414 | 415 | #[derive(Debug, PartialEq)] 416 | pub enum DOMAttributeValue { 417 | Boolean(bool), 418 | Number(f64), 419 | Char(char), 420 | Str(DOMText), 421 | Styles(S), 422 | Prop(Prop), 423 | EventListener(Closure), 424 | Node(DOMNode) 425 | } 426 | -------------------------------------------------------------------------------- /rsx-dom/src/util.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use types::{Closure, DOMAttribute, DOMAttributeName, DOMAttributeValue, DOMText, EventType, KnownAttributeName}; 13 | 14 | pub fn is_event_listener(attribute: &DOMAttribute) -> Option<&Closure> { 15 | use self::DOMAttributeName::KnownName; 16 | use self::DOMAttributeValue::EventListener; 17 | use self::KnownAttributeName::Style; 18 | match attribute { 19 | &DOMAttribute(KnownName(Style), EventListener(ref l)) => Some(l), 20 | _ => None 21 | } 22 | } 23 | 24 | pub fn is_src(attribute: &DOMAttribute) -> Option<&DOMText> { 25 | use self::DOMAttributeName::KnownName; 26 | use self::DOMAttributeValue::Str; 27 | use self::KnownAttributeName::Src; 28 | match attribute { 29 | &DOMAttribute(KnownName(Src), Str(ref s)) => Some(s), 30 | _ => None 31 | } 32 | } 33 | 34 | pub fn is_style(attribute: &DOMAttribute) -> Option<&S> { 35 | use self::DOMAttributeName::KnownName; 36 | use self::DOMAttributeValue::Styles; 37 | use self::KnownAttributeName::Style; 38 | match attribute { 39 | &DOMAttribute(KnownName(Style), Styles(ref s)) => Some(s), 40 | _ => None 41 | } 42 | } 43 | 44 | pub fn find_attribute<'a, E, S, C, L, I>(iter: I, name: &DOMAttributeName) -> Option<&'a DOMAttribute> 45 | where 46 | I: IntoIterator> 47 | { 48 | iter.into_iter().find(|v| &v.0 == name) 49 | } 50 | 51 | pub fn find_event_listener<'a, E: 'a, S: 'a, C: 'a, L: 'a, I>(iter: I, ty: EventType) -> Option<&'a Closure> 52 | where 53 | I: IntoIterator> 54 | { 55 | let name = DOMAttributeName::EventType(ty); 56 | is_event_listener(find_attribute(iter, &name)?) 57 | } 58 | 59 | pub fn find_src<'a, E: 'a, S: 'a, C: 'a, L: 'a, I>(iter: I) -> Option<&'a DOMText> 60 | where 61 | I: IntoIterator> 62 | { 63 | let name = DOMAttributeName::KnownName(KnownAttributeName::Src); 64 | is_src(find_attribute(iter, &name)?) 65 | } 66 | 67 | pub fn find_styles<'a, E: 'a, S: 'a, C: 'a, L: 'a, I>(iter: I) -> Option<&'a S> 68 | where 69 | I: IntoIterator> 70 | { 71 | let name = DOMAttributeName::KnownName(KnownAttributeName::Style); 72 | is_style(find_attribute(iter, &name)?) 73 | } 74 | -------------------------------------------------------------------------------- /rsx-dom/tests/spec_quote.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | // #[macro_use] 13 | // extern crate quote; 14 | // extern crate rsx_dom; 15 | // extern crate syn; 16 | 17 | // use rsx_dom::rsx_parser::parse; 18 | 19 | // #[test] 20 | // fn test_from_rsx_1() { 21 | // let (ast, _) = parse("
").unwrap(); 22 | 23 | // let tokens = quote! { DOMNode::from(DOMTagName::from(KnownElementName::Div)) }; 24 | 25 | // assert_eq!( 26 | // syn::parse_expr(quote! { #ast }.as_str()), 27 | // syn::parse_expr(tokens.as_str()) 28 | // ); 29 | // } 30 | 31 | // #[test] 32 | // fn test_from_rsx_2() { 33 | // let (ast, _) = parse("").unwrap(); 34 | 35 | // let tokens = quote! { DOMNode::from(DOMTagName::from("foo-bar")) }; 36 | 37 | // assert_eq!( 38 | // syn::parse_expr(quote! { #ast }.as_str()), 39 | // syn::parse_expr(tokens.as_str()) 40 | // ); 41 | // } 42 | 43 | // #[test] 44 | // fn test_from_rsx_3() { 45 | // let (ast, _) = parse("").unwrap(); 46 | 47 | // let tokens = quote! { DOMNode::from(DOMTagName::from(("foo", "bar"))) }; 48 | 49 | // assert_eq!( 50 | // syn::parse_expr(quote! { #ast }.as_str()), 51 | // syn::parse_expr(tokens.as_str()) 52 | // ); 53 | // } 54 | 55 | // #[test] 56 | // fn test_from_rsx_4() { 57 | // let (ast, _) = parse("").unwrap(); 58 | 59 | // let tokens = quote! { DOMNode::from(DOMTagName::from(box ["foo", "bar"])) }; 60 | 61 | // assert_eq!( 62 | // syn::parse_expr(quote! { #ast }.as_str()), 63 | // syn::parse_expr(tokens.as_str()) 64 | // ); 65 | // } 66 | 67 | // #[test] 68 | // fn test_from_rsx_5() { 69 | // let (ast, _) = parse("
").unwrap(); 70 | 71 | // let tokens = quote! { 72 | // DOMNode::from(( 73 | // DOMTagName::from(KnownElementName::Div), 74 | // box [ 75 | // DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 76 | // ] 77 | // )) 78 | // }; 79 | 80 | // assert_eq!( 81 | // syn::parse_expr(quote! { #ast }.as_str()), 82 | // syn::parse_expr(tokens.as_str()) 83 | // ); 84 | // } 85 | 86 | // #[test] 87 | // fn test_from_rsx_6() { 88 | // let (ast, _) = parse("
").unwrap(); 89 | 90 | // let tokens = quote! { 91 | // DOMNode::from(( 92 | // DOMTagName::from(KnownElementName::Div), 93 | // box [ 94 | // DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 95 | // ] 96 | // )) 97 | // }; 98 | 99 | // assert_eq!( 100 | // syn::parse_expr(quote! { #ast }.as_str()), 101 | // syn::parse_expr(tokens.as_str()) 102 | // ); 103 | // } 104 | 105 | // #[test] 106 | // fn test_from_rsx_7() { 107 | // let (ast, _) = parse("
").unwrap(); 108 | 109 | // let tokens = quote! { 110 | // DOMNode::from(( 111 | // DOMTagName::from(KnownElementName::Div), 112 | // box [ 113 | // DOMAttribute::from(( 114 | // DOMAttributeName::from("foo"), 115 | // DOMAttributeValue::from(42f64) 116 | // )), 117 | // ] 118 | // )) 119 | // }; 120 | 121 | // assert_eq!( 122 | // syn::parse_expr(quote! { #ast }.as_str()), 123 | // syn::parse_expr(tokens.as_str()) 124 | // ); 125 | // } 126 | 127 | // #[test] 128 | // fn test_from_rsx_8() { 129 | // let (ast, _) = parse("
").unwrap(); 130 | 131 | // let tokens = quote! { 132 | // DOMNode::from(( 133 | // DOMTagName::from(KnownElementName::Div), 134 | // box [ 135 | // DOMAttribute::from(( 136 | // DOMAttributeName::from("foo"), 137 | // DOMAttributeValue::from("bar") 138 | // )), 139 | // ] 140 | // )) 141 | // }; 142 | 143 | // assert_eq!( 144 | // syn::parse_expr(quote! { #ast }.as_str()), 145 | // syn::parse_expr(tokens.as_str()) 146 | // ); 147 | // } 148 | 149 | // #[test] 150 | // fn test_from_rsx_9() { 151 | // let (ast, _) = parse("
").unwrap(); 152 | 153 | // let tokens = quote! { 154 | // DOMNode::from(( 155 | // DOMTagName::from(KnownElementName::Div), 156 | // box [ 157 | // DOMAttribute::from(( 158 | // DOMAttributeName::from("foo"), 159 | // DOMAttributeValue::from("bar") 160 | // )), 161 | // ] 162 | // )) 163 | // }; 164 | 165 | // assert_eq!( 166 | // syn::parse_expr(quote! { #ast }.as_str()), 167 | // syn::parse_expr(tokens.as_str()) 168 | // ); 169 | // } 170 | 171 | // #[test] 172 | // fn test_from_rsx_10() { 173 | // let (ast, _) = parse("
").unwrap(); 174 | 175 | // let tokens = quote! { 176 | // DOMNode::from(( 177 | // DOMTagName::from(KnownElementName::Div), 178 | // box [ 179 | // DOMAttribute::from(( 180 | // DOMAttributeName::from("foo"), 181 | // DOMAttributeValue::from("bar") 182 | // )), 183 | // ] 184 | // )) 185 | // }; 186 | 187 | // assert_eq!( 188 | // syn::parse_expr(quote! { #ast }.as_str()), 189 | // syn::parse_expr(tokens.as_str()) 190 | // ); 191 | // } 192 | 193 | // #[test] 194 | // fn test_from_rsx_11() { 195 | // let (ast, _) = parse("
").unwrap(); 196 | 197 | // let tokens = quote! { 198 | // DOMNode::from(( 199 | // DOMTagName::from(KnownElementName::Div), 200 | // box [ 201 | // DOMAttribute::from(( 202 | // DOMAttributeName::from("foo"), 203 | // DOMAttributeValue::from("bar") 204 | // )), 205 | // ] 206 | // )) 207 | // }; 208 | 209 | // assert_eq!( 210 | // syn::parse_expr(quote! { #ast }.as_str()), 211 | // syn::parse_expr(tokens.as_str()) 212 | // ); 213 | // } 214 | 215 | // #[test] 216 | // fn test_from_rsx_12() { 217 | // let (ast, _) = parse("
>
").unwrap(); 218 | 219 | // let tokens = quote! { 220 | // DOMNode::from(( 221 | // DOMTagName::from(KnownElementName::Div), 222 | // box [ 223 | // DOMAttribute::from(( 224 | // DOMAttributeName::from("foo"), 225 | // DOMAttributeValue::from(DOMNode::from(DOMTagName::from("bar"))) 226 | // )), 227 | // ] 228 | // )) 229 | // }; 230 | 231 | // assert_eq!( 232 | // syn::parse_expr(quote! { #ast }.as_str()), 233 | // syn::parse_expr(tokens.as_str()) 234 | // ); 235 | // } 236 | 237 | // #[test] 238 | // fn test_from_rsx_13() { 239 | // let (ast, _) = parse("bar").unwrap(); 240 | 241 | // let tokens = quote! { DOMNode::from((DOMTagName::from("foo"), box [DOMNode::from("bar")])) }; 242 | 243 | // assert_eq!( 244 | // syn::parse_expr(quote! { #ast }.as_str()), 245 | // syn::parse_expr(tokens.as_str()) 246 | // ); 247 | // } 248 | 249 | // #[test] 250 | // fn test_from_rsx_14() { 251 | // let (ast, _) = parse("").unwrap(); 252 | 253 | // let tokens = quote! { 254 | // DOMNode::from(( 255 | // DOMTagName::from("foo"), 256 | // box [DOMNode::from(DOMTagName::from("bar"))] 257 | // )) 258 | // }; 259 | 260 | // assert_eq!( 261 | // syn::parse_expr(quote! { #ast }.as_str()), 262 | // syn::parse_expr(tokens.as_str()) 263 | // ); 264 | // } 265 | 266 | // #[test] 267 | // fn test_from_rsx_15() { 268 | // let (ast, _) = parse("baz").unwrap(); 269 | 270 | // let tokens = quote! { 271 | // DOMNode::from(( 272 | // DOMTagName::from("foo"), 273 | // box [DOMNode::from(DOMTagName::from("bar")), DOMNode::from("baz")] 274 | // )) 275 | // }; 276 | 277 | // assert_eq!( 278 | // syn::parse_expr(quote! { #ast }.as_str()), 279 | // syn::parse_expr(tokens.as_str()) 280 | // ); 281 | // } 282 | -------------------------------------------------------------------------------- /rsx-dom/tests/spec_runtime.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | #![feature(never_type)] 13 | #![feature(try_from)] 14 | #![feature(box_syntax)] 15 | 16 | #[macro_use] 17 | extern crate rsx_dom; 18 | extern crate rsx_shared; 19 | 20 | use std::convert::TryInto; 21 | 22 | use rsx_dom::types::*; 23 | use rsx_shared::traits::*; 24 | use rsx_shared::types::{ 25 | DummyComputedBorderStyle, 26 | DummyComputedBoxShadow, 27 | DummyComputedColor, 28 | DummyComputedCursor, 29 | DummyComputedFontCaps, 30 | DummyComputedFontName, 31 | DummyComputedFontSize, 32 | DummyComputedFontStretch, 33 | DummyComputedFontStyle, 34 | DummyComputedFontWeight, 35 | DummyComputedTextShadow, 36 | DummyComputedVisibility 37 | }; 38 | 39 | type DOMNode = rsx_dom::types::DOMNode<(), (), MockComputedStyles, MockLayoutNode>; 40 | 41 | #[derive(Debug, PartialEq, Clone, Default)] 42 | struct MockComputedStyles(Vec); 43 | 44 | impl TComputedStyles for MockComputedStyles { 45 | type BackgroundColor = DummyComputedColor; 46 | type Opacity = u32; 47 | type BorderSize = u32; 48 | type BorderColor = DummyComputedColor; 49 | type BorderStyle = DummyComputedBorderStyle; 50 | type BoxShadow = DummyComputedBoxShadow; 51 | 52 | fn make_initial_computed_styles(_: T) -> Self 53 | where 54 | T: TryInto 55 | { 56 | MockComputedStyles(Vec::new()) 57 | } 58 | 59 | fn reset_custom_styles(&mut self, _: T) 60 | where 61 | T: TryInto 62 | { 63 | unimplemented!() 64 | } 65 | 66 | fn apply_rules<'a, I>(&mut self, _: I) 67 | where 68 | I: Iterator 69 | { 70 | self.0.push("apply_rules()".to_string()); 71 | } 72 | 73 | fn apply_styles(&mut self, _: &Self::Styles) { 74 | self.0.push("apply_styles()".to_string()); 75 | } 76 | 77 | fn background_color(&self) -> Self::BackgroundColor { 78 | unimplemented!() 79 | } 80 | 81 | fn opacity(&self) -> Self::Opacity { 82 | unimplemented!() 83 | } 84 | 85 | fn border_bottom_width(&self) -> Self::BorderSize { 86 | unimplemented!() 87 | } 88 | 89 | fn border_bottom_color(&self) -> Self::BorderColor { 90 | unimplemented!() 91 | } 92 | 93 | fn border_bottom_style(&self) -> Self::BorderStyle { 94 | unimplemented!() 95 | } 96 | 97 | fn border_left_width(&self) -> Self::BorderSize { 98 | unimplemented!() 99 | } 100 | 101 | fn border_left_color(&self) -> Self::BorderColor { 102 | unimplemented!() 103 | } 104 | 105 | fn border_left_style(&self) -> Self::BorderStyle { 106 | unimplemented!() 107 | } 108 | 109 | fn border_right_width(&self) -> Self::BorderSize { 110 | unimplemented!() 111 | } 112 | 113 | fn border_right_color(&self) -> Self::BorderColor { 114 | unimplemented!() 115 | } 116 | 117 | fn border_right_style(&self) -> Self::BorderStyle { 118 | unimplemented!() 119 | } 120 | 121 | fn border_top_width(&self) -> Self::BorderSize { 122 | unimplemented!() 123 | } 124 | 125 | fn border_top_color(&self) -> Self::BorderColor { 126 | unimplemented!() 127 | } 128 | 129 | fn border_top_style(&self) -> Self::BorderStyle { 130 | unimplemented!() 131 | } 132 | 133 | fn box_shadows_copy(&self) -> Vec { 134 | unimplemented!() 135 | } 136 | } 137 | 138 | impl TInheritedStyles for MockComputedStyles { 139 | type Styles = (); 140 | type Cursor = DummyComputedCursor; 141 | type Color = DummyComputedColor; 142 | type TextShadow = DummyComputedTextShadow; 143 | type FontName = DummyComputedFontName; 144 | type FontStyle = DummyComputedFontStyle; 145 | type FontCaps = DummyComputedFontCaps; 146 | type FontWeight = DummyComputedFontWeight; 147 | type FontSize = DummyComputedFontSize; 148 | type FontStretch = DummyComputedFontStretch; 149 | type Visibility = DummyComputedVisibility; 150 | 151 | fn inherit_styles(&mut self, _: &Self) { 152 | self.0.push("inherit_styles()".to_string()); 153 | } 154 | 155 | fn cursor(&self) -> Self::Cursor { 156 | unimplemented!() 157 | } 158 | 159 | fn color(&self) -> Self::Color { 160 | unimplemented!() 161 | } 162 | 163 | fn text_shadows_copy(&self) -> Vec { 164 | unimplemented!() 165 | } 166 | 167 | fn font_names_copy(&self) -> Vec { 168 | unimplemented!() 169 | } 170 | 171 | fn font_style(&self) -> Self::FontStyle { 172 | unimplemented!() 173 | } 174 | 175 | fn font_caps(&self) -> Self::FontCaps { 176 | unimplemented!() 177 | } 178 | 179 | fn font_weight(&self) -> Self::FontWeight { 180 | unimplemented!() 181 | } 182 | 183 | fn font_size(&self) -> Self::FontSize { 184 | unimplemented!() 185 | } 186 | 187 | fn font_stretch(&self) -> Self::FontStretch { 188 | unimplemented!() 189 | } 190 | 191 | fn visibility(&self) -> Self::Visibility { 192 | unimplemented!() 193 | } 194 | 195 | fn find_font(&self, _: F) -> Option 196 | where 197 | F: FnMut(&Self::FontName) -> Option 198 | { 199 | unimplemented!() 200 | } 201 | } 202 | 203 | #[derive(Debug, PartialEq, Default)] 204 | struct MockLayoutNode(Vec); 205 | 206 | impl TLayoutNode for MockLayoutNode { 207 | type Styles = (); 208 | type Resources = (); 209 | type TextMeasureMetadata = MockComputedStyles; 210 | type ImageMeasureMetadata = (); 211 | type NormalMeasureMetadata = !; 212 | type ReflowDirection = (); 213 | type ClientPosition = (); 214 | type BoundingClientRect = (); 215 | type MeasuredImage = (); 216 | type ShapedText = (); 217 | 218 | fn make_initial_layout_node(_: T) -> Self 219 | where 220 | T: TryInto 221 | { 222 | Default::default() 223 | } 224 | 225 | fn reset_custom_styles(&mut self, _: T) 226 | where 227 | T: TryInto 228 | { 229 | unimplemented!() 230 | } 231 | 232 | fn is_tainted(&self) -> bool { 233 | false 234 | } 235 | 236 | fn insert_child(&mut self, _: &mut Self, _: usize) { 237 | unimplemented!() 238 | } 239 | 240 | fn append_child(&mut self, _: &mut Self) { 241 | self.0.push("append_child()".to_string()); 242 | } 243 | 244 | fn remove_child(&mut self, _: &mut Self) { 245 | unimplemented!() 246 | } 247 | 248 | fn apply_rules<'a, I>(&mut self, _: I) 249 | where 250 | I: Iterator 251 | { 252 | self.0.push("apply_rules()".to_string()); 253 | } 254 | 255 | fn apply_styles(&mut self, _: &Self::Styles) { 256 | self.0.push("apply_styles()".to_string()); 257 | } 258 | 259 | fn mark_dirty(&mut self) { 260 | unimplemented!() 261 | } 262 | 263 | fn measure_self_as_text(&mut self, _: &Self::Resources, t: &T, _: &Self::TextMeasureMetadata) 264 | where 265 | T: TDOMText 266 | { 267 | self.0.push(format!("measure_self_as_text({:?})", t)); 268 | } 269 | 270 | fn measure_self_as_image(&mut self, _: &Self::Resources, t: &T, _: &Self::ImageMeasureMetadata) 271 | where 272 | T: TDOMText 273 | { 274 | self.0.push(format!("measure_self_as_image({:?})", t)); 275 | } 276 | 277 | fn measure_self_as_normal(&mut self, _: &Self::Resources, _: &Self::NormalMeasureMetadata) { 278 | unreachable!() 279 | } 280 | 281 | fn reflow_subtree(&mut self, w: u32, h: u32, d: Self::ReflowDirection) { 282 | let string = format!("reflow_subtree({:?}, {:?}, {:?})", w, h, d); 283 | self.0.push(string); 284 | } 285 | 286 | fn set_computed_client_position(&mut self, _: Self::ClientPosition) { 287 | unimplemented!() 288 | } 289 | 290 | fn get_local_bounding_client_rect(&self) -> Self::BoundingClientRect { 291 | unimplemented!() 292 | } 293 | 294 | fn get_global_bounding_client_rect(&self) -> Self::BoundingClientRect { 295 | unimplemented!() 296 | } 297 | 298 | fn get_measured_image(&self) -> &Self::MeasuredImage { 299 | unimplemented!() 300 | } 301 | 302 | fn get_shaped_text(&self) -> &Self::ShapedText { 303 | unimplemented!() 304 | } 305 | } 306 | 307 | #[test] 308 | fn test_simple_traverse() { 309 | let tree = fragment! { 310 | DOMNode::from(( 311 | DOMTagName::from(KnownElementName::Div), 312 | vec![ 313 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 314 | ], 315 | vec![ 316 | DOMNode::from(( 317 | DOMTagName::from("bar"), 318 | vec![ 319 | DOMAttribute::from(( 320 | DOMAttributeName::from("baz"), 321 | DOMAttributeValue::from(false) 322 | )), 323 | ], 324 | vec![DOMNode::from("Hello")] 325 | )), 326 | DOMNode::from({ "world" }), 327 | DOMNode::from({ "!" }), 328 | ] 329 | )) 330 | }; 331 | 332 | let node = tree.document(); 333 | 334 | assert_eq!( 335 | node.descendants_iter().collect::>(), 336 | vec![ 337 | &DOMNode::from(( 338 | DOMTagName::from(KnownElementName::Div), 339 | vec![ 340 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 341 | ] 342 | )), 343 | &DOMNode::from(( 344 | DOMTagName::from("bar"), 345 | vec![ 346 | DOMAttribute::from(( 347 | DOMAttributeName::from("baz"), 348 | DOMAttributeValue::from(false) 349 | )), 350 | ] 351 | )), 352 | &DOMNode::from("Hello"), 353 | &DOMNode::from("world"), 354 | &DOMNode::from("!"), 355 | ] 356 | ); 357 | } 358 | 359 | #[test] 360 | #[cfg(feature = "hashmap-arena")] 361 | fn test_nested_traverse() { 362 | let build_subtree = || { 363 | fragment! { 364 | DOMNode::from(( 365 | DOMTagName::from(KnownElementName::View), 366 | vec![ 367 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 368 | ], 369 | vec![ 370 | DOMNode::from(( 371 | DOMTagName::from("bar"), 372 | vec![ 373 | DOMAttribute::from(( 374 | DOMAttributeName::from("baz"), 375 | DOMAttributeValue::from(false) 376 | )), 377 | ], 378 | vec![DOMNode::from("Hello")] 379 | )), 380 | DOMNode::from({ "world" }), 381 | DOMNode::from({ "!" }) 382 | ] 383 | )) 384 | } 385 | }; 386 | 387 | let build_tree = || { 388 | fragment! { 389 | DOMNode::from(( 390 | DOMTagName::from(KnownElementName::Div), 391 | vec![ 392 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 393 | ], 394 | vec![ 395 | DOMNode::from({ 396 | build_subtree() 397 | }) 398 | ] 399 | )) 400 | } 401 | }; 402 | 403 | let tree = build_tree(); 404 | let node = tree.document(); 405 | 406 | assert_eq!( 407 | node.descendants_iter().collect::>(), 408 | vec![ 409 | &DOMNode::from(( 410 | DOMTagName::from(KnownElementName::Div), 411 | vec![ 412 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 413 | ] 414 | )), 415 | &DOMNode::from(( 416 | DOMTagName::from(KnownElementName::View), 417 | vec![ 418 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 419 | ] 420 | )), 421 | &DOMNode::from(( 422 | DOMTagName::from("bar"), 423 | vec![ 424 | DOMAttribute::from(( 425 | DOMAttributeName::from("baz"), 426 | DOMAttributeValue::from(false) 427 | )), 428 | ] 429 | )), 430 | &DOMNode::from("Hello"), 431 | &DOMNode::from("world"), 432 | &DOMNode::from("!"), 433 | ] 434 | ); 435 | } 436 | 437 | #[test] 438 | fn test_simple_computed_styles() { 439 | let mut tree = fragment! { 440 | DOMNode::from(( 441 | DOMTagName::from(KnownElementName::Div), 442 | vec![ 443 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 444 | ], 445 | vec![ 446 | DOMNode::from(( 447 | DOMTagName::from(KnownElementName::Image), 448 | vec![ 449 | DOMAttribute::from(( 450 | DOMAttributeName::from(KnownAttributeName::Src), 451 | DOMAttributeValue::from("url") 452 | )), 453 | ] 454 | )), 455 | DOMNode::from(( 456 | DOMTagName::from("bar"), 457 | vec![ 458 | DOMAttribute::from(( 459 | DOMAttributeName::from("baz"), 460 | DOMAttributeValue::from(false) 461 | )), 462 | ], 463 | vec![DOMNode::from("Hello")] 464 | )), 465 | DOMNode::from({ "world" }), 466 | DOMNode::from({ "!" }), 467 | ] 468 | )) 469 | }; 470 | 471 | assert_eq!( 472 | tree.document() 473 | .descendants_iter() 474 | .map(|v| v.computed_styles()) 475 | .collect::>(), 476 | vec![ 477 | &MockComputedStyles(vec![ 478 | "apply_styles()".to_string(), 479 | "apply_rules()".to_string(), 480 | ]), 481 | &MockComputedStyles(vec![ 482 | "apply_styles()".to_string(), 483 | "apply_rules()".to_string(), 484 | ]), 485 | &MockComputedStyles(vec![ 486 | "apply_styles()".to_string(), 487 | "apply_rules()".to_string(), 488 | ]), 489 | &MockComputedStyles(vec![ 490 | "apply_styles()".to_string(), 491 | "apply_rules()".to_string(), 492 | ]), 493 | &MockComputedStyles(vec![ 494 | "apply_styles()".to_string(), 495 | "apply_rules()".to_string(), 496 | ]), 497 | &MockComputedStyles(vec![ 498 | "apply_styles()".to_string(), 499 | "apply_rules()".to_string(), 500 | ]), 501 | ], 502 | ); 503 | 504 | tree.generate_layout_tree(&()); 505 | 506 | assert_eq!( 507 | tree.document() 508 | .descendants_iter() 509 | .map(|v| v.computed_styles()) 510 | .collect::>(), 511 | vec![ 512 | &MockComputedStyles(vec![ 513 | "apply_styles()".to_string(), 514 | "apply_rules()".to_string(), 515 | ]), 516 | &MockComputedStyles(vec![ 517 | "apply_styles()".to_string(), 518 | "apply_rules()".to_string(), 519 | ]), 520 | &MockComputedStyles(vec![ 521 | "apply_styles()".to_string(), 522 | "apply_rules()".to_string(), 523 | ]), 524 | &MockComputedStyles(vec![ 525 | "apply_styles()".to_string(), 526 | "apply_rules()".to_string(), 527 | "inherit_styles()".to_string(), 528 | ]), 529 | &MockComputedStyles(vec![ 530 | "apply_styles()".to_string(), 531 | "apply_rules()".to_string(), 532 | "inherit_styles()".to_string(), 533 | ]), 534 | &MockComputedStyles(vec![ 535 | "apply_styles()".to_string(), 536 | "apply_rules()".to_string(), 537 | "inherit_styles()".to_string(), 538 | ]), 539 | ], 540 | ); 541 | } 542 | 543 | #[test] 544 | fn test_simple_layout() { 545 | let mut tree = fragment! { 546 | DOMNode::from(( 547 | DOMTagName::from(KnownElementName::Div), 548 | vec![ 549 | DOMAttribute::from((DOMAttributeName::from("foo"), DOMAttributeValue::from(true))), 550 | ], 551 | vec![ 552 | DOMNode::from(( 553 | DOMTagName::from(KnownElementName::Image), 554 | vec![ 555 | DOMAttribute::from(( 556 | DOMAttributeName::from(KnownAttributeName::Src), 557 | DOMAttributeValue::from("url") 558 | )), 559 | ] 560 | )), 561 | DOMNode::from(( 562 | DOMTagName::from("bar"), 563 | vec![ 564 | DOMAttribute::from(( 565 | DOMAttributeName::from("baz"), 566 | DOMAttributeValue::from(false) 567 | )), 568 | ], 569 | vec![DOMNode::from("Hello")] 570 | )), 571 | DOMNode::from({ "world" }), 572 | DOMNode::from({ "!" }), 573 | ] 574 | )) 575 | }; 576 | 577 | assert_eq!( 578 | tree.document() 579 | .descendants_iter() 580 | .map(|v| v.computed_styles()) 581 | .collect::>(), 582 | vec![ 583 | &MockComputedStyles(vec![ 584 | "apply_styles()".to_string(), 585 | "apply_rules()".to_string(), 586 | ]), 587 | &MockComputedStyles(vec![ 588 | "apply_styles()".to_string(), 589 | "apply_rules()".to_string(), 590 | ]), 591 | &MockComputedStyles(vec![ 592 | "apply_styles()".to_string(), 593 | "apply_rules()".to_string(), 594 | ]), 595 | &MockComputedStyles(vec![ 596 | "apply_styles()".to_string(), 597 | "apply_rules()".to_string(), 598 | ]), 599 | &MockComputedStyles(vec![ 600 | "apply_styles()".to_string(), 601 | "apply_rules()".to_string(), 602 | ]), 603 | &MockComputedStyles(vec![ 604 | "apply_styles()".to_string(), 605 | "apply_rules()".to_string(), 606 | ]), 607 | ], 608 | ); 609 | 610 | tree.generate_layout_tree(&()); 611 | 612 | assert_eq!( 613 | tree.document() 614 | .descendants_iter() 615 | .map(|v| v.layout_node()) 616 | .collect::>(), 617 | vec![ 618 | &MockLayoutNode(vec![ 619 | "apply_styles()".to_string(), 620 | "apply_rules()".to_string(), 621 | "append_child()".to_string(), 622 | "append_child()".to_string(), 623 | "append_child()".to_string(), 624 | "append_child()".to_string(), 625 | ]), 626 | &MockLayoutNode(vec![ 627 | "apply_styles()".to_string(), 628 | "apply_rules()".to_string(), 629 | "measure_self_as_image(Static(\"url\"))".to_string(), 630 | ]), 631 | &MockLayoutNode(vec![ 632 | "apply_styles()".to_string(), 633 | "apply_rules()".to_string(), 634 | "append_child()".to_string(), 635 | ]), 636 | &MockLayoutNode(vec![ 637 | "apply_styles()".to_string(), 638 | "apply_rules()".to_string(), 639 | "measure_self_as_text(Static(\"Hello\"))".to_string(), 640 | ]), 641 | &MockLayoutNode(vec![ 642 | "apply_styles()".to_string(), 643 | "apply_rules()".to_string(), 644 | "measure_self_as_text(Static(\"world\"))".to_string(), 645 | ]), 646 | &MockLayoutNode(vec![ 647 | "apply_styles()".to_string(), 648 | "apply_rules()".to_string(), 649 | "measure_self_as_text(Static(\"!\"))".to_string(), 650 | ]), 651 | ], 652 | ); 653 | } 654 | -------------------------------------------------------------------------------- /rsx-tree/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsx-tree" 3 | version = "0.1.0" 4 | authors = ["Victor Porof "] 5 | 6 | [lib] 7 | name = "rsx_tree" 8 | 9 | [features] 10 | vec-arena = [] 11 | hashmap-arena = [] 12 | 13 | [dependencies] 14 | rsx-arena = { path = "../rsx-arena", default-features = false } -------------------------------------------------------------------------------- /rsx-tree/src/iter.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use types::Ref; 13 | 14 | #[derive(Debug)] 15 | pub struct Children<'a, T: 'a> { 16 | front: Option>, 17 | back: Option> 18 | } 19 | 20 | impl<'a, 'b, T: 'a> From<&'b Ref<'a, T>> for Children<'a, T> { 21 | fn from(root: &Ref<'a, T>) -> Self { 22 | Children { 23 | front: root.first_child(), 24 | back: root.last_child() 25 | } 26 | } 27 | } 28 | 29 | impl<'a, T: 'a> Eq for Children<'a, T> {} 30 | 31 | impl<'a, T: 'a> PartialEq for Children<'a, T> { 32 | fn eq(&self, other: &Self) -> bool { 33 | self.front == other.front && self.back == other.back 34 | } 35 | } 36 | 37 | impl<'a, T: 'a> Copy for Children<'a, T> {} 38 | 39 | impl<'a, T: 'a> Clone for Children<'a, T> { 40 | fn clone(&self) -> Self { 41 | *self 42 | } 43 | } 44 | 45 | impl<'a, T: 'a> Iterator for Children<'a, T> { 46 | type Item = Ref<'a, T>; 47 | 48 | fn next(&mut self) -> Option { 49 | if self.front == self.back { 50 | let node = self.front.take(); 51 | self.back = None; 52 | node 53 | } else { 54 | let node = self.front.take(); 55 | self.front = node.and_then(|v| v.next_sibling()); 56 | node 57 | } 58 | } 59 | } 60 | 61 | #[derive(Debug)] 62 | pub enum Edge<'a, T: 'a> { 63 | Open(Ref<'a, T>), 64 | Close(Ref<'a, T>) 65 | } 66 | 67 | impl<'a, T: 'a> Eq for Edge<'a, T> {} 68 | 69 | impl<'a, T: 'a> PartialEq for Edge<'a, T> { 70 | fn eq(&self, other: &Self) -> bool { 71 | match (self, other) { 72 | (&Edge::Open(a), &Edge::Open(b)) | (&Edge::Close(a), &Edge::Close(b)) => a == b, 73 | _ => false 74 | } 75 | } 76 | } 77 | 78 | impl<'a, T: 'a> Copy for Edge<'a, T> {} 79 | 80 | impl<'a, T: 'a> Clone for Edge<'a, T> { 81 | fn clone(&self) -> Self { 82 | *self 83 | } 84 | } 85 | 86 | impl<'a, T: 'a> Edge<'a, T> { 87 | pub fn node(self) -> Ref<'a, T> { 88 | match self { 89 | Edge::Open(v) | Edge::Close(v) => v 90 | } 91 | } 92 | } 93 | 94 | #[derive(Debug)] 95 | pub struct Traverse<'a, T: 'a> { 96 | root: Ref<'a, T>, 97 | edge: Option> 98 | } 99 | 100 | impl<'a, 'b, T: 'a> From<&'b Ref<'a, T>> for Traverse<'a, T> { 101 | fn from(root: &Ref<'a, T>) -> Self { 102 | let root = *root; 103 | let edge = None; 104 | Traverse { root, edge } 105 | } 106 | } 107 | 108 | impl<'a, T: 'a> Eq for Traverse<'a, T> {} 109 | 110 | impl<'a, T: 'a> PartialEq for Traverse<'a, T> { 111 | fn eq(&self, other: &Self) -> bool { 112 | self.root == other.root && self.edge == other.edge 113 | } 114 | } 115 | 116 | impl<'a, T: 'a> Copy for Traverse<'a, T> {} 117 | 118 | impl<'a, T: 'a> Clone for Traverse<'a, T> { 119 | fn clone(&self) -> Self { 120 | *self 121 | } 122 | } 123 | 124 | impl<'a, T: 'a> Iterator for Traverse<'a, T> { 125 | type Item = Edge<'a, T>; 126 | 127 | fn next(&mut self) -> Option { 128 | match self.edge { 129 | None => { 130 | self.edge = Some(Edge::Open(self.root)); 131 | } 132 | Some(Edge::Open(node)) => { 133 | if let Some(first_child) = node.first_child() { 134 | self.edge = Some(Edge::Open(first_child)); 135 | } else { 136 | self.edge = Some(Edge::Close(node)); 137 | } 138 | } 139 | Some(Edge::Close(node)) => { 140 | if node == self.root { 141 | self.edge = None; 142 | } else if let Some(next_sibling) = node.next_sibling() { 143 | self.edge = Some(Edge::Open(next_sibling)); 144 | } else { 145 | self.edge = node.parent().map(Edge::Close); 146 | } 147 | } 148 | } 149 | self.edge 150 | } 151 | } 152 | 153 | #[derive(Debug)] 154 | pub struct Descendants<'a, T: 'a> { 155 | iter: Traverse<'a, T> 156 | } 157 | 158 | impl<'a, 'b, T: 'a> From<&'b Ref<'a, T>> for Descendants<'a, T> { 159 | fn from(root: &Ref<'a, T>) -> Self { 160 | Descendants { 161 | iter: Traverse::from(root) 162 | } 163 | } 164 | } 165 | 166 | impl<'a, T: 'a> Eq for Descendants<'a, T> {} 167 | 168 | impl<'a, T: 'a> PartialEq for Descendants<'a, T> { 169 | fn eq(&self, other: &Self) -> bool { 170 | self.iter == other.iter 171 | } 172 | } 173 | 174 | impl<'a, T: 'a> Copy for Descendants<'a, T> {} 175 | 176 | impl<'a, T: 'a> Clone for Descendants<'a, T> { 177 | fn clone(&self) -> Self { 178 | *self 179 | } 180 | } 181 | 182 | impl<'a, T: 'a> Iterator for Descendants<'a, T> { 183 | type Item = Ref<'a, T>; 184 | 185 | fn next(&mut self) -> Option { 186 | loop { 187 | match self.iter.next() { 188 | Some(Edge::Open(node)) => return Some(node), 189 | Some(Edge::Close(_)) => {} 190 | None => return None 191 | } 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /rsx-tree/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | #![feature(conservative_impl_trait)] 13 | 14 | extern crate rsx_arena; 15 | 16 | mod iter; 17 | mod node; 18 | mod node_id; 19 | mod node_ref; 20 | mod node_ref_mut; 21 | mod node_ref_mut_pair; 22 | mod tree; 23 | 24 | pub mod types { 25 | pub use iter::*; 26 | pub use node::*; 27 | pub use node_id::*; 28 | pub use node_ref::*; 29 | pub use node_ref_mut::*; 30 | pub use node_ref_mut_pair::*; 31 | pub use tree::*; 32 | } 33 | -------------------------------------------------------------------------------- /rsx-tree/src/node.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use types::Id; 13 | 14 | #[derive(Debug, PartialEq)] 15 | pub struct Node { 16 | pub(crate) parent_id: Option>, 17 | pub(crate) prev_sibling_id: Option>, 18 | pub(crate) next_sibling_id: Option>, 19 | pub(crate) first_child_id: Option>, 20 | pub(crate) last_child_id: Option>, 21 | pub(crate) value: T 22 | } 23 | 24 | impl Node { 25 | pub(crate) fn new(value: T) -> Self { 26 | Node { 27 | parent_id: None, 28 | prev_sibling_id: None, 29 | next_sibling_id: None, 30 | first_child_id: None, 31 | last_child_id: None, 32 | value 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rsx-tree/src/node_id.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use rsx_arena::types::ArenaItemId; 13 | 14 | use types::Node; 15 | 16 | pub type Id = ArenaItemId>; 17 | pub type IdPair = (Id, Id); 18 | -------------------------------------------------------------------------------- /rsx-tree/src/node_ref.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use types::{Children, Descendants, Id, Node, Traverse, Tree}; 13 | 14 | #[derive(Debug)] 15 | pub struct Ref<'a, T: 'a> { 16 | cached: Option<&'a Node>, 17 | tree: &'a Tree, 18 | id: Id 19 | } 20 | 21 | impl<'a, T: 'a> Eq for Ref<'a, T> {} 22 | 23 | impl<'a, T: 'a> PartialEq for Ref<'a, T> { 24 | fn eq(&self, other: &Self) -> bool { 25 | self.id == other.id 26 | } 27 | } 28 | 29 | impl<'a, T: 'a> Copy for Ref<'a, T> {} 30 | 31 | impl<'a, T: 'a> Clone for Ref<'a, T> { 32 | fn clone(&self) -> Self { 33 | *self 34 | } 35 | } 36 | 37 | impl<'a, T: 'a> Ref<'a, T> { 38 | pub(crate) fn new(tree: &'a Tree, id: Id) -> Self { 39 | let cached = tree.arena.get(id); 40 | Ref { cached, tree, id } 41 | } 42 | 43 | pub fn tree(&self) -> &'a Tree { 44 | self.tree 45 | } 46 | 47 | pub fn id(&self) -> Id { 48 | self.id 49 | } 50 | 51 | pub fn try_value(&self) -> Option<&'a T> { 52 | Some(&self.cached?.value) 53 | } 54 | 55 | pub fn try_into_value(self) -> Option<&'a T> { 56 | Some(&self.cached?.value) 57 | } 58 | 59 | pub fn parent_id(&self) -> Option> { 60 | self.cached?.parent_id 61 | } 62 | 63 | pub fn parent(&self) -> Option> { 64 | let id = self.parent_id()?; 65 | Some(self.tree.get(id)) 66 | } 67 | 68 | pub fn prev_sibling_id(&self) -> Option> { 69 | self.cached?.prev_sibling_id 70 | } 71 | 72 | pub fn prev_sibling(&self) -> Option> { 73 | let id = self.prev_sibling_id()?; 74 | Some(self.tree.get(id)) 75 | } 76 | 77 | pub fn next_sibling_id(&self) -> Option> { 78 | self.cached?.next_sibling_id 79 | } 80 | 81 | pub fn next_sibling(&self) -> Option> { 82 | let id = self.next_sibling_id()?; 83 | Some(self.tree.get(id)) 84 | } 85 | 86 | pub fn first_child_id(&self) -> Option> { 87 | self.cached?.first_child_id 88 | } 89 | 90 | pub fn first_child(&self) -> Option> { 91 | let id = self.first_child_id()?; 92 | Some(self.tree.get(id)) 93 | } 94 | 95 | pub fn last_child_id(&self) -> Option> { 96 | self.cached?.last_child_id 97 | } 98 | 99 | pub fn last_child(&self) -> Option> { 100 | let id = self.last_child_id()?; 101 | Some(self.tree.get(id)) 102 | } 103 | 104 | pub fn sibling_ids(&self) -> (Option>, Option>) { 105 | if let Some(node) = self.tree.arena.get(self.id) { 106 | (node.prev_sibling_id, node.next_sibling_id) 107 | } else { 108 | (None, None) 109 | } 110 | } 111 | 112 | pub fn edge_ids(&self) -> (Option>, Option>) { 113 | if let Some(node) = self.tree.arena.get(self.id) { 114 | (node.first_child_id, node.last_child_id) 115 | } else { 116 | (None, None) 117 | } 118 | } 119 | 120 | pub fn children_refs_iter(&self) -> Children<'a, T> { 121 | Children::from(self) 122 | } 123 | 124 | pub fn children_ids_iter(&self) -> impl Iterator> + 'a { 125 | self.children_refs_iter().map(|v| v.id()) 126 | } 127 | 128 | pub fn children_values_iter(&self) -> impl Iterator { 129 | self.children_refs_iter().filter_map(|v| v.try_value()) 130 | } 131 | 132 | pub fn descendants_refs_iter(&self) -> Descendants<'a, T> { 133 | Descendants::from(self) 134 | } 135 | 136 | pub fn descendants_ids_iter(&self) -> impl Iterator> + 'a { 137 | self.descendants_refs_iter().map(|v| v.id()) 138 | } 139 | 140 | pub fn descendants_values_iter(&self) -> impl Iterator { 141 | self.descendants_refs_iter().filter_map(|v| v.try_value()) 142 | } 143 | 144 | pub fn traverse_edges_iter(&self) -> Traverse<'a, T> { 145 | Traverse::from(self) 146 | } 147 | 148 | pub fn traverse_refs_iter(&self) -> impl Iterator> { 149 | self.traverse_edges_iter().map(|v| v.node()) 150 | } 151 | 152 | pub fn traverse_ids_iter(&self) -> impl Iterator> + 'a { 153 | self.traverse_refs_iter().map(|v| v.id()) 154 | } 155 | 156 | pub fn traverse_values_iter(&self) -> impl Iterator { 157 | self.traverse_refs_iter().filter_map(|v| v.try_value()) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /rsx-tree/src/node_ref_mut.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use types::{Id, Ref, Tree}; 13 | 14 | #[derive(Debug)] 15 | pub struct RefMut<'a, T: 'a> { 16 | tree: &'a mut Tree, 17 | id: Id 18 | } 19 | 20 | impl<'a, T: 'a> Eq for RefMut<'a, T> {} 21 | 22 | impl<'a, T: 'a> PartialEq for RefMut<'a, T> { 23 | fn eq(&self, other: &Self) -> bool { 24 | self.id == other.id 25 | } 26 | } 27 | 28 | impl<'a, T> Into> for RefMut<'a, T> { 29 | fn into(self) -> Ref<'a, T> { 30 | Ref::new(self.tree, self.id) 31 | } 32 | } 33 | 34 | impl<'a, T: 'a> RefMut<'a, T> { 35 | pub(crate) fn new(tree: &'a mut Tree, id: Id) -> Self { 36 | RefMut { tree, id } 37 | } 38 | 39 | pub fn tree(&self) -> &Tree { 40 | self.tree 41 | } 42 | 43 | pub fn tree_mut(&mut self) -> &mut Tree { 44 | &mut self.tree 45 | } 46 | 47 | pub fn id(&self) -> Id { 48 | self.id 49 | } 50 | 51 | pub fn try_value(&self) -> Option<&T> { 52 | Some(&self.tree.arena.get(self.id)?.value) 53 | } 54 | 55 | pub fn try_value_mut(&mut self) -> Option<&mut T> { 56 | Some(&mut self.tree.arena.get_mut(self.id)?.value) 57 | } 58 | 59 | pub fn try_into_value(self) -> Option<&'a mut T> { 60 | Some(&mut self.tree.arena.get_mut(self.id)?.value) 61 | } 62 | 63 | pub fn parent_id(&self) -> Option> { 64 | self.tree.arena.get(self.id)?.parent_id 65 | } 66 | 67 | pub fn parent(&mut self) -> Option> { 68 | let id = self.parent_id()?; 69 | Some(self.tree.get_mut(id)) 70 | } 71 | 72 | pub fn prev_sibling_id(&self) -> Option> { 73 | self.tree.arena.get(self.id)?.prev_sibling_id 74 | } 75 | 76 | pub fn prev_sibling(&mut self) -> Option> { 77 | let id = self.prev_sibling_id()?; 78 | Some(self.tree.get_mut(id)) 79 | } 80 | 81 | pub fn next_sibling_id(&self) -> Option> { 82 | self.tree.arena.get(self.id)?.next_sibling_id 83 | } 84 | 85 | pub fn next_sibling(&mut self) -> Option> { 86 | let id = self.next_sibling_id()?; 87 | Some(self.tree.get_mut(id)) 88 | } 89 | 90 | pub fn first_child_id(&self) -> Option> { 91 | self.tree.arena.get(self.id)?.first_child_id 92 | } 93 | 94 | pub fn first_child(&mut self) -> Option> { 95 | let id = self.first_child_id()?; 96 | Some(self.tree.get_mut(id)) 97 | } 98 | 99 | pub fn last_child_id(&self) -> Option> { 100 | self.tree.arena.get(self.id)?.last_child_id 101 | } 102 | 103 | pub fn last_child(&mut self) -> Option> { 104 | let id = self.last_child_id()?; 105 | Some(self.tree.get_mut(id)) 106 | } 107 | 108 | pub fn sibling_ids(&self) -> (Option>, Option>) { 109 | if let Some(node) = self.tree.arena.get(self.id) { 110 | (node.prev_sibling_id, node.next_sibling_id) 111 | } else { 112 | (None, None) 113 | } 114 | } 115 | 116 | pub fn edge_ids(&self) -> (Option>, Option>) { 117 | if let Some(node) = self.tree.arena.get(self.id) { 118 | (node.first_child_id, node.last_child_id) 119 | } else { 120 | (None, None) 121 | } 122 | } 123 | 124 | pub fn append_tree(&mut self, other: Tree) -> bool { 125 | let children: Vec<_> = other.get(other.root()).children_ids_iter().collect(); 126 | self.tree.arena += other.arena; 127 | children.into_iter().all(|id| self.append_id(id).is_some()) 128 | } 129 | 130 | pub fn prepend_tree(&mut self, other: Tree) -> bool { 131 | let children: Vec<_> = other.get(other.root()).children_ids_iter().collect(); 132 | self.tree.arena += other.arena; 133 | children.into_iter().all(|id| self.prepend_id(id).is_some()) 134 | } 135 | 136 | pub fn append(&mut self, value: T) -> RefMut { 137 | let id = self.tree.alloc(value); 138 | self.append_id(id); 139 | self.tree.get_mut(id) 140 | } 141 | 142 | pub fn prepend(&mut self, value: T) -> RefMut { 143 | let id = self.tree.alloc(value); 144 | self.prepend_id(id); 145 | self.tree.get_mut(id) 146 | } 147 | 148 | pub fn detach(&mut self) { 149 | self.detach_own_id(); 150 | } 151 | 152 | pub fn append_id(&mut self, child_id: Id) -> Option<()> { 153 | let old_last_child_id = self.tree.arena.get(self.id)?.last_child_id; 154 | 155 | // Update the new node's parent and previous sibling. 156 | { 157 | let new_child_node = self.tree.arena.get_mut(child_id)?; 158 | new_child_node.parent_id = Some(self.id); 159 | new_child_node.prev_sibling_id = old_last_child_id; 160 | } 161 | 162 | // Update the old last child's next sibling. 163 | if let Some(old_last_child_id) = old_last_child_id { 164 | let last_child_node = self.tree.arena.get_mut(old_last_child_id)?; 165 | last_child_node.next_sibling_id = Some(child_id); 166 | } 167 | 168 | // Update this node's first and last child. 169 | { 170 | let this_node = self.tree.arena.get_mut(self.id)?; 171 | this_node.last_child_id = Some(child_id); 172 | if this_node.first_child_id == None { 173 | this_node.first_child_id = this_node.last_child_id; 174 | } 175 | } 176 | 177 | Some(()) 178 | } 179 | 180 | pub fn prepend_id(&mut self, child_id: Id) -> Option<()> { 181 | let old_first_child_id = self.tree.arena.get(self.id)?.first_child_id; 182 | 183 | // Update the new node's parent and next sibling. 184 | { 185 | let new_child_node = self.tree.arena.get_mut(child_id)?; 186 | new_child_node.parent_id = Some(self.id); 187 | new_child_node.next_sibling_id = old_first_child_id; 188 | } 189 | 190 | // Update the old first child's prev sibling. 191 | if let Some(old_first_child_id) = old_first_child_id { 192 | let old_first_child_node = self.tree.arena.get_mut(old_first_child_id)?; 193 | old_first_child_node.prev_sibling_id = Some(child_id); 194 | } 195 | 196 | // Update this node's first and last child. 197 | { 198 | let this_node = self.tree.arena.get_mut(self.id)?; 199 | this_node.first_child_id = Some(child_id); 200 | if this_node.last_child_id == None { 201 | this_node.last_child_id = this_node.first_child_id; 202 | } 203 | } 204 | 205 | Some(()) 206 | } 207 | 208 | pub fn detach_own_id(&mut self) -> Option<()> { 209 | let old_parent_id = self.parent_id()?; 210 | let (old_prev_sibling_id, old_next_sibling_id) = self.sibling_ids(); 211 | 212 | // Update this node's parent, prev and next siblings. 213 | { 214 | let this_node = self.tree.arena.get_mut(self.id)?; 215 | this_node.parent_id = None; 216 | this_node.prev_sibling_id = None; 217 | this_node.next_sibling_id = None; 218 | } 219 | 220 | // Link the old prev and next siblings together. 221 | if let Some(old_prev_sibling_id) = old_prev_sibling_id { 222 | let old_prev_sibling_node = self.tree.arena.get_mut(old_prev_sibling_id)?; 223 | old_prev_sibling_node.next_sibling_id = old_next_sibling_id; 224 | } 225 | 226 | if let Some(old_next_sibling_id) = old_next_sibling_id { 227 | let old_next_sibling_node = self.tree.arena.get_mut(old_next_sibling_id)?; 228 | old_next_sibling_node.prev_sibling_id = old_prev_sibling_id; 229 | } 230 | 231 | // Update the old parent node's first and last children. 232 | let old_parent_node = self.tree.arena.get_mut(old_parent_id)?; 233 | let old_parents_first_child_id = old_parent_node.first_child_id; 234 | let old_parents_last_child_id = old_parent_node.last_child_id; 235 | 236 | if old_parents_first_child_id == old_parents_last_child_id { 237 | old_parent_node.first_child_id = None; 238 | old_parent_node.last_child_id = None; 239 | } else if old_parents_first_child_id == Some(self.id) { 240 | old_parent_node.first_child_id = old_next_sibling_id; 241 | old_parent_node.last_child_id = old_parents_last_child_id; 242 | } else if old_parents_last_child_id == Some(self.id) { 243 | old_parent_node.first_child_id = old_parents_first_child_id; 244 | old_parent_node.last_child_id = old_prev_sibling_id; 245 | } 246 | 247 | Some(()) 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /rsx-tree/src/node_ref_mut_pair.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | use types::{IdPair, Tree}; 13 | 14 | #[derive(Debug)] 15 | pub struct RefMutPair<'a, T: 'a> { 16 | tree: &'a mut Tree, 17 | ids: IdPair 18 | } 19 | 20 | impl<'a, T: 'a> Eq for RefMutPair<'a, T> {} 21 | 22 | impl<'a, T: 'a> PartialEq for RefMutPair<'a, T> { 23 | fn eq(&self, other: &Self) -> bool { 24 | self.ids == other.ids 25 | } 26 | } 27 | 28 | impl<'a, T: 'a> RefMutPair<'a, T> { 29 | pub(crate) fn new(tree: &'a mut Tree, ids: IdPair) -> Self { 30 | RefMutPair { tree, ids } 31 | } 32 | 33 | pub fn try_values(&mut self) -> Option<(&mut T, &mut T)> { 34 | let (first, second) = self.tree.arena.get_mut_pair(self.ids.0, self.ids.1); 35 | Some((&mut first?.value, &mut second?.value)) 36 | } 37 | 38 | pub fn try_into_values(self) -> Option<(&'a mut T, &'a mut T)> { 39 | let (first, second) = self.tree.arena.get_mut_pair(self.ids.0, self.ids.1); 40 | Some((&mut first?.value, &mut second?.value)) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rsx-tree/src/tree.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Mozilla 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed 7 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | #[cfg(all(not(feature = "vec-arena"), not(feature = "hashmap-arena")))] 13 | use rsx_arena::types::VecArena as Arena; 14 | 15 | #[cfg(feature = "hashmap-arena")] 16 | use rsx_arena::types::HashmapArena as Arena; 17 | #[cfg(feature = "vec-arena")] 18 | use rsx_arena::types::VecArena as Arena; 19 | 20 | use types::{Id, IdPair, Node, Ref, RefMut, RefMutPair}; 21 | 22 | #[derive(Debug, PartialEq)] 23 | pub struct Tree { 24 | pub(crate) arena: Arena>, 25 | pub(crate) root: Id 26 | } 27 | 28 | impl Tree { 29 | pub fn new(root: U) -> Self 30 | where 31 | U: Into 32 | { 33 | let mut arena = Arena::new(); 34 | let root = arena.alloc(Node::new(U::into(root))); 35 | Tree { arena, root } 36 | } 37 | 38 | pub fn root(&self) -> Id { 39 | self.root 40 | } 41 | 42 | pub fn alloc(&mut self, value: U) -> Id 43 | where 44 | U: Into 45 | { 46 | self.arena.alloc(Node::new(U::into(value))) 47 | } 48 | 49 | pub fn get(&self, id: Id) -> Ref { 50 | Ref::new(self, id) 51 | } 52 | 53 | pub fn get_mut(&mut self, id: Id) -> RefMut { 54 | RefMut::new(self, id) 55 | } 56 | 57 | pub fn get_mut_pair(&mut self, ids: IdPair) -> RefMutPair { 58 | RefMutPair::new(self, ids) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2017-11-14 -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | error_on_line_overflow = false 2 | format_strings = true 3 | imports_indent = "Block" 4 | imports_layout = "HorizontalVertical" 5 | max_width = 140 6 | reorder_extern_crates = true 7 | reorder_extern_crates_in_group = true 8 | reorder_imported_names = true 9 | reorder_imports = true 10 | reorder_imports_in_group = true 11 | trailing_comma = "Never" --------------------------------------------------------------------------------