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

//! The implementation of the DOM.
//!
//! The DOM is comprised of interfaces (defined by specifications using
//! [WebIDL](https://heycam.github.io/webidl/)) that are implemented as Rust
//! structs in submodules of this module. Its implementation is documented
//! below.
//!
//! A DOM object and its reflector
//! ==============================
//!
//! The implementation of an interface `Foo` in Servo's DOM involves two
//! related but distinct objects:
//!
//! * the **DOM object**: an instance of the Rust struct `dom::foo::Foo`
//!   (marked with the `#[dom_struct]` attribute) on the Rust heap;
//! * the **reflector**: a `JSObject` allocated by SpiderMonkey, that owns the
//!   DOM object.
//!
//! Memory management
//! =================
//!
//! Reflectors of DOM objects, and thus the DOM objects themselves, are managed
//! by the SpiderMonkey Garbage Collector. Thus, keeping alive a DOM object
//! is done through its reflector.
//!
//! For more information, see:
//!
//! * rooting pointers on the stack:
//!   the [`Root`](bindings/js/struct.Root.html) smart pointer;
//! * tracing pointers in member fields: the [`JS`](bindings/js/struct.JS.html),
//!   [`MutNullableHeap`](bindings/js/struct.MutNullableHeap.html) and
//!   [`MutHeap`](bindings/js/struct.MutHeap.html) smart pointers and
//!   [the tracing implementation](bindings/trace/index.html);
//! * rooting pointers from across thread boundaries or in channels: the
//!   [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer;
//!
//! Inheritance
//! ===========
//!
//! Rust does not support struct inheritance, as would be used for the
//! object-oriented DOM APIs. To work around this issue, Servo stores an
//! instance of the superclass in the first field of its subclasses. (Note that
//! it is stored by value, rather than in a smart pointer such as `JS<T>`.)
//!
//! This implies that a pointer to an object can safely be cast to a pointer
//! to all its classes.
//!
//! This invariant is enforced by the lint in
//! `plugins::lints::inheritance_integrity`.
//!
//! Interfaces which either derive from or are derived by other interfaces
//! implement the `Castable` trait, which provides three methods `is::<T>()`,
//! `downcast::<T>()` and `upcast::<T>()` to cast across the type hierarchy
//! and check whether a given instance is of a given type.
//!
//! ```ignore
//! use dom::bindings::inheritance::Castable;
//! use dom::element::Element;
//! use dom::htmlelement::HTMLElement;
//! use dom::htmlinputelement::HTMLInputElement;
//!
//! if let Some(elem) = node.downcast::<Element> {
//!     if elem.is::<HTMLInputElement>() {
//!         return elem.upcast::<HTMLElement>();
//!     }
//! }
//! ```
//!
//! Furthermore, when discriminating a given instance against multiple
//! interface types, code generation provides a convenient TypeId enum
//! which can be used to write `match` expressions instead of multiple
//! calls to `Castable::is::<T>`. The `type_id()` method of an instance is
//! provided by the farthest interface it derives from, e.g. `EventTarget`
//! for `HTMLMediaElement`. For convenience, that method is also provided
//! on the `Node` interface to avoid unnecessary upcasts to `EventTarget`.
//!
//! ```ignore
//! use dom::bindings::inheritance::{EventTargetTypeId, NodeTypeId};
//!
//! match *node.type_id() {
//!     EventTargetTypeId::Node(NodeTypeId::CharacterData(_)) => ...,
//!     EventTargetTypeId::Node(NodeTypeId::Element(_)) => ...,
//!     ...,
//! }
//! ```
//!
//! Construction
//! ============
//!
//! DOM objects of type `T` in Servo have two constructors:
//!
//! * a `T::new_inherited` static method that returns a plain `T`, and
//! * a `T::new` static method that returns `Root<T>`.
//!
//! (The result of either method can be wrapped in `Result`, if that is
//! appropriate for the type in question.)
//!
//! The latter calls the former, boxes the result, and creates a reflector
//! corresponding to it by calling `dom::bindings::utils::reflect_dom_object`
//! (which yields ownership of the object to the SpiderMonkey Garbage Collector).
//! This is the API to use when creating a DOM object.
//!
//! The former should only be called by the latter, and by subclasses'
//! `new_inherited` methods.
//!
//! DOM object constructors in JavaScript correspond to a `T::Constructor`
//! static method. This method is always fallible.
//!
//! Destruction
//! ===========
//!
//! When the SpiderMonkey Garbage Collector discovers that the reflector of a
//! DOM object is garbage, it calls the reflector's finalization hook. This
//! function deletes the reflector's DOM object, calling its destructor in the
//! process.
//!
//! Mutability and aliasing
//! =======================
//!
//! Reflectors are JavaScript objects, and as such can be freely aliased. As
//! Rust does not allow mutable aliasing, mutable borrows of DOM objects are
//! not allowed. In particular, any mutable fields use `Cell` or `DOMRefCell`
//! to manage their mutability.
//!
//! `Reflector` and `Reflectable`
//! =============================
//!
//! Every DOM object has a `Reflector` as its first (transitive) member field.
//! This contains a `*mut JSObject` that points to its reflector.
//!
//! The `FooBinding::Wrap` function creates the reflector, stores a pointer to
//! the DOM object in the reflector, and initializes the pointer to the reflector
//! in the `Reflector` field.
//!
//! The `Reflectable` trait provides a `reflector()` method that returns the
//! DOM object's `Reflector`. It is implemented automatically for DOM structs
//! through the `#[dom_struct]` attribute.
//!
//! Implementing methods for a DOM object
//! =====================================
//!
//! * `dom::bindings::codegen::Bindings::FooBindings::FooMethods` for methods
//!   defined through IDL;
//! * `&self` public methods for public helpers;
//! * `&self` methods for private helpers.
//!
//! Accessing fields of a DOM object
//! ================================
//!
//! All fields of DOM objects are private; accessing them from outside their
//! module is done through explicit getter or setter methods.
//!
//! Inheritance and casting
//! =======================
//!
//! For all DOM interfaces `Foo` in an inheritance chain, a
//! `dom::bindings::inheritance::FooCast` provides methods to cast
//! to other types in the inheritance chain. For example:
//!
//! ```ignore
//! # use script::dom::bindings::inheritance::{NodeCast, HTMLElementCast};
//! # use script::dom::element::Element;
//! # use script::dom::node::Node;
//! # use script::dom::htmlelement::HTMLElement;
//! fn f(element: &Element) {
//!     let base = element.upcast::<Node>();
//!     let derived = element.downcast::<HTMLElement>();
//! }
//! ```
//!
//! Adding a new DOM interface
//! ==========================
//!
//! Adding a new interface `Foo` requires at least the following:
//!
//! * adding the new IDL file at `components/script/dom/webidls/Foo.webidl`;
//! * creating `components/script/dom/foo.rs`;
//! * listing `foo.rs` in `components/script/dom/mod.rs`;
//! * defining the DOM struct `Foo` with a `#[dom_struct]` attribute, a
//!   superclass or `Reflector` member, and other members as appropriate;
//! * implementing the
//!   `dom::bindings::codegen::Bindings::FooBindings::FooMethods` trait for
//!   `Foo`;
//! * adding/updating the match arm in create_element in
//!   `components/script/dom/create.rs` (only applicable to new types inheriting
//!   from `HTMLElement`)
//!
//! More information is available in the [bindings module](bindings/index.html).
//!
//! Accessing DOM objects from layout
//! =================================
//!
//! Layout code can access the DOM through the
//! [`LayoutJS`](bindings/js/struct.LayoutJS.html) smart pointer. This does not
//! keep the DOM object alive; we ensure that no DOM code (Garbage Collection
//! in particular) runs while the layout thread is accessing the DOM.
//!
//! Methods accessible to layout are implemented on `LayoutJS<Foo>` using
//! `LayoutFooHelpers` traits.

#[macro_use]
pub mod macros;

pub mod types {
    include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs"));
}

pub mod activation;
pub mod attr;
pub mod beforeunloadevent;
mod create;
#[allow(unsafe_code)]
#[deny(missing_docs, non_snake_case)]
pub mod bindings;
pub mod blob;
pub mod bluetooth;
pub mod bluetoothadvertisingdata;
pub mod bluetoothcharacteristicproperties;
pub mod bluetoothdevice;
pub mod bluetoothremotegattcharacteristic;
pub mod bluetoothremotegattdescriptor;
pub mod bluetoothremotegattserver;
pub mod bluetoothremotegattservice;
pub mod bluetoothuuid;
pub mod browsingcontext;
pub mod canvasgradient;
pub mod canvaspattern;
pub mod canvasrenderingcontext2d;
pub mod characterdata;
pub mod closeevent;
pub mod comment;
pub mod console;
pub mod crypto;
pub mod css;
pub mod cssstyledeclaration;
pub mod customevent;
pub mod dedicatedworkerglobalscope;
pub mod document;
pub mod documentfragment;
pub mod documenttype;
pub mod domexception;
pub mod domimplementation;
pub mod domparser;
pub mod dompoint;
pub mod dompointreadonly;
pub mod domquad;
pub mod domrect;
pub mod domrectlist;
pub mod domrectreadonly;
pub mod domstringmap;
pub mod domtokenlist;
pub mod element;
pub mod errorevent;
pub mod event;
pub mod eventdispatcher;
pub mod eventsource;
pub mod eventtarget;
pub mod file;
pub mod filelist;
pub mod filereader;
pub mod focusevent;
pub mod forcetouchevent;
pub mod formdata;
pub mod hashchangeevent;
pub mod htmlanchorelement;
pub mod htmlappletelement;
pub mod htmlareaelement;
pub mod htmlaudioelement;
pub mod htmlbaseelement;
pub mod htmlbodyelement;
pub mod htmlbrelement;
pub mod htmlbuttonelement;
pub mod htmlcanvaselement;
pub mod htmlcollection;
pub mod htmldataelement;
pub mod htmldatalistelement;
pub mod htmldetailselement;
pub mod htmldialogelement;
pub mod htmldirectoryelement;
pub mod htmldivelement;
pub mod htmldlistelement;
pub mod htmlelement;
pub mod htmlembedelement;
pub mod htmlfieldsetelement;
pub mod htmlfontelement;
pub mod htmlformcontrolscollection;
pub mod htmlformelement;
pub mod htmlframeelement;
pub mod htmlframesetelement;
pub mod htmlheadelement;
pub mod htmlheadingelement;
pub mod htmlhrelement;
pub mod htmlhtmlelement;
pub mod htmliframeelement;
pub mod htmlimageelement;
pub mod htmlinputelement;
pub mod htmllabelelement;
pub mod htmllegendelement;
pub mod htmllielement;
pub mod htmllinkelement;
pub mod htmlmapelement;
pub mod htmlmediaelement;
pub mod htmlmetaelement;
pub mod htmlmeterelement;
pub mod htmlmodelement;
pub mod htmlobjectelement;
pub mod htmlolistelement;
pub mod htmloptgroupelement;
pub mod htmloptionelement;
pub mod htmloutputelement;
pub mod htmlparagraphelement;
pub mod htmlparamelement;
pub mod htmlpreelement;
pub mod htmlprogresselement;
pub mod htmlquoteelement;
pub mod htmlscriptelement;
pub mod htmlselectelement;
pub mod htmlsourceelement;
pub mod htmlspanelement;
pub mod htmlstyleelement;
pub mod htmltablecaptionelement;
pub mod htmltablecellelement;
pub mod htmltablecolelement;
pub mod htmltabledatacellelement;
pub mod htmltableelement;
pub mod htmltableheadercellelement;
pub mod htmltablerowelement;
pub mod htmltablesectionelement;
pub mod htmltemplateelement;
pub mod htmltextareaelement;
pub mod htmltimeelement;
pub mod htmltitleelement;
pub mod htmltrackelement;
pub mod htmlulistelement;
pub mod htmlunknownelement;
pub mod htmlvideoelement;
pub mod imagedata;
pub mod keyboardevent;
pub mod location;
pub mod mediaerror;
pub mod messageevent;
pub mod mimetype;
pub mod mimetypearray;
pub mod mouseevent;
pub mod namednodemap;
pub mod navigator;
pub mod navigatorinfo;
pub mod node;
pub mod nodeiterator;
pub mod nodelist;
pub mod pagetransitionevent;
pub mod performance;
pub mod performancetiming;
pub mod plugin;
pub mod pluginarray;
pub mod popstateevent;
pub mod processinginstruction;
pub mod progressevent;
pub mod radionodelist;
pub mod range;
pub mod screen;
pub mod servohtmlparser;
pub mod servoxmlparser;
pub mod storage;
pub mod storageevent;
pub mod stylesheet;
pub mod stylesheetlist;
pub mod testbinding;
pub mod testbindingproxy;
pub mod text;
pub mod textdecoder;
pub mod textencoder;
pub mod touch;
pub mod touchevent;
pub mod touchlist;
pub mod treewalker;
pub mod uievent;
pub mod url;
pub mod urlhelper;
pub mod urlsearchparams;
pub mod userscripts;
pub mod validation;
pub mod validitystate;
pub mod values;
pub mod virtualmethods;
pub mod webglactiveinfo;
pub mod webglbuffer;
pub mod webglcontextevent;
pub mod webglframebuffer;
pub mod webglobject;
pub mod webglprogram;
pub mod webglrenderbuffer;
pub mod webglrenderingcontext;
pub mod webglshader;
pub mod webglshaderprecisionformat;
pub mod webgltexture;
pub mod webgluniformlocation;
pub mod websocket;
pub mod window;
pub mod worker;
pub mod workerglobalscope;
pub mod workerlocation;
pub mod workernavigator;
pub mod xmldocument;
pub mod xmlhttprequest;
pub mod xmlhttprequesteventtarget;
pub mod xmlhttprequestupload;
<commit_msg>Fix the doc on inheritance and casting<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The implementation of the DOM.
//!
//! The DOM is comprised of interfaces (defined by specifications using
//! [WebIDL](https://heycam.github.io/webidl/)) that are implemented as Rust
//! structs in submodules of this module. Its implementation is documented
//! below.
//!
//! A DOM object and its reflector
//! ==============================
//!
//! The implementation of an interface `Foo` in Servo's DOM involves two
//! related but distinct objects:
//!
//! * the **DOM object**: an instance of the Rust struct `dom::foo::Foo`
//!   (marked with the `#[dom_struct]` attribute) on the Rust heap;
//! * the **reflector**: a `JSObject` allocated by SpiderMonkey, that owns the
//!   DOM object.
//!
//! Memory management
//! =================
//!
//! Reflectors of DOM objects, and thus the DOM objects themselves, are managed
//! by the SpiderMonkey Garbage Collector. Thus, keeping alive a DOM object
//! is done through its reflector.
//!
//! For more information, see:
//!
//! * rooting pointers on the stack:
//!   the [`Root`](bindings/js/struct.Root.html) smart pointer;
//! * tracing pointers in member fields: the [`JS`](bindings/js/struct.JS.html),
//!   [`MutNullableHeap`](bindings/js/struct.MutNullableHeap.html) and
//!   [`MutHeap`](bindings/js/struct.MutHeap.html) smart pointers and
//!   [the tracing implementation](bindings/trace/index.html);
//! * rooting pointers from across thread boundaries or in channels: the
//!   [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer;
//!
//! Inheritance
//! ===========
//!
//! Rust does not support struct inheritance, as would be used for the
//! object-oriented DOM APIs. To work around this issue, Servo stores an
//! instance of the superclass in the first field of its subclasses. (Note that
//! it is stored by value, rather than in a smart pointer such as `JS<T>`.)
//!
//! This implies that a pointer to an object can safely be cast to a pointer
//! to all its classes.
//!
//! This invariant is enforced by the lint in
//! `plugins::lints::inheritance_integrity`.
//!
//! Interfaces which either derive from or are derived by other interfaces
//! implement the `Castable` trait, which provides three methods `is::<T>()`,
//! `downcast::<T>()` and `upcast::<T>()` to cast across the type hierarchy
//! and check whether a given instance is of a given type.
//!
//! ```ignore
//! use dom::bindings::inheritance::Castable;
//! use dom::element::Element;
//! use dom::htmlelement::HTMLElement;
//! use dom::htmlinputelement::HTMLInputElement;
//!
//! if let Some(elem) = node.downcast::<Element> {
//!     if elem.is::<HTMLInputElement>() {
//!         return elem.upcast::<HTMLElement>();
//!     }
//! }
//! ```
//!
//! Furthermore, when discriminating a given instance against multiple
//! interface types, code generation provides a convenient TypeId enum
//! which can be used to write `match` expressions instead of multiple
//! calls to `Castable::is::<T>`. The `type_id()` method of an instance is
//! provided by the farthest interface it derives from, e.g. `EventTarget`
//! for `HTMLMediaElement`. For convenience, that method is also provided
//! on the `Node` interface to avoid unnecessary upcasts to `EventTarget`.
//!
//! ```ignore
//! use dom::bindings::inheritance::{EventTargetTypeId, NodeTypeId};
//!
//! match *node.type_id() {
//!     EventTargetTypeId::Node(NodeTypeId::CharacterData(_)) => ...,
//!     EventTargetTypeId::Node(NodeTypeId::Element(_)) => ...,
//!     ...,
//! }
//! ```
//!
//! Construction
//! ============
//!
//! DOM objects of type `T` in Servo have two constructors:
//!
//! * a `T::new_inherited` static method that returns a plain `T`, and
//! * a `T::new` static method that returns `Root<T>`.
//!
//! (The result of either method can be wrapped in `Result`, if that is
//! appropriate for the type in question.)
//!
//! The latter calls the former, boxes the result, and creates a reflector
//! corresponding to it by calling `dom::bindings::utils::reflect_dom_object`
//! (which yields ownership of the object to the SpiderMonkey Garbage Collector).
//! This is the API to use when creating a DOM object.
//!
//! The former should only be called by the latter, and by subclasses'
//! `new_inherited` methods.
//!
//! DOM object constructors in JavaScript correspond to a `T::Constructor`
//! static method. This method is always fallible.
//!
//! Destruction
//! ===========
//!
//! When the SpiderMonkey Garbage Collector discovers that the reflector of a
//! DOM object is garbage, it calls the reflector's finalization hook. This
//! function deletes the reflector's DOM object, calling its destructor in the
//! process.
//!
//! Mutability and aliasing
//! =======================
//!
//! Reflectors are JavaScript objects, and as such can be freely aliased. As
//! Rust does not allow mutable aliasing, mutable borrows of DOM objects are
//! not allowed. In particular, any mutable fields use `Cell` or `DOMRefCell`
//! to manage their mutability.
//!
//! `Reflector` and `Reflectable`
//! =============================
//!
//! Every DOM object has a `Reflector` as its first (transitive) member field.
//! This contains a `*mut JSObject` that points to its reflector.
//!
//! The `FooBinding::Wrap` function creates the reflector, stores a pointer to
//! the DOM object in the reflector, and initializes the pointer to the reflector
//! in the `Reflector` field.
//!
//! The `Reflectable` trait provides a `reflector()` method that returns the
//! DOM object's `Reflector`. It is implemented automatically for DOM structs
//! through the `#[dom_struct]` attribute.
//!
//! Implementing methods for a DOM object
//! =====================================
//!
//! * `dom::bindings::codegen::Bindings::FooBindings::FooMethods` for methods
//!   defined through IDL;
//! * `&self` public methods for public helpers;
//! * `&self` methods for private helpers.
//!
//! Accessing fields of a DOM object
//! ================================
//!
//! All fields of DOM objects are private; accessing them from outside their
//! module is done through explicit getter or setter methods.
//!
//! Inheritance and casting
//! =======================
//!
//! All DOM interfaces part of an inheritance chain (i.e. interfaces
//! that derive others or are derived from) implement the trait `Castable`
//! which provides both downcast and upcasts.
//!
//! ```ignore
//! # use script::dom::bindings::inheritance::Castable;
//! # use script::dom::element::Element;
//! # use script::dom::node::Node;
//! # use script::dom::htmlelement::HTMLElement;
//! fn f(element: &Element) {
//!     let base = element.upcast::<Node>();
//!     let derived = element.downcast::<HTMLElement>().unwrap();
//! }
//! ```
//!
//! Adding a new DOM interface
//! ==========================
//!
//! Adding a new interface `Foo` requires at least the following:
//!
//! * adding the new IDL file at `components/script/dom/webidls/Foo.webidl`;
//! * creating `components/script/dom/foo.rs`;
//! * listing `foo.rs` in `components/script/dom/mod.rs`;
//! * defining the DOM struct `Foo` with a `#[dom_struct]` attribute, a
//!   superclass or `Reflector` member, and other members as appropriate;
//! * implementing the
//!   `dom::bindings::codegen::Bindings::FooBindings::FooMethods` trait for
//!   `Foo`;
//! * adding/updating the match arm in create_element in
//!   `components/script/dom/create.rs` (only applicable to new types inheriting
//!   from `HTMLElement`)
//!
//! More information is available in the [bindings module](bindings/index.html).
//!
//! Accessing DOM objects from layout
//! =================================
//!
//! Layout code can access the DOM through the
//! [`LayoutJS`](bindings/js/struct.LayoutJS.html) smart pointer. This does not
//! keep the DOM object alive; we ensure that no DOM code (Garbage Collection
//! in particular) runs while the layout thread is accessing the DOM.
//!
//! Methods accessible to layout are implemented on `LayoutJS<Foo>` using
//! `LayoutFooHelpers` traits.

#[macro_use]
pub mod macros;

pub mod types {
    include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs"));
}

pub mod activation;
pub mod attr;
pub mod beforeunloadevent;
mod create;
#[allow(unsafe_code)]
#[deny(missing_docs, non_snake_case)]
pub mod bindings;
pub mod blob;
pub mod bluetooth;
pub mod bluetoothadvertisingdata;
pub mod bluetoothcharacteristicproperties;
pub mod bluetoothdevice;
pub mod bluetoothremotegattcharacteristic;
pub mod bluetoothremotegattdescriptor;
pub mod bluetoothremotegattserver;
pub mod bluetoothremotegattservice;
pub mod bluetoothuuid;
pub mod browsingcontext;
pub mod canvasgradient;
pub mod canvaspattern;
pub mod canvasrenderingcontext2d;
pub mod characterdata;
pub mod closeevent;
pub mod comment;
pub mod console;
pub mod crypto;
pub mod css;
pub mod cssstyledeclaration;
pub mod customevent;
pub mod dedicatedworkerglobalscope;
pub mod document;
pub mod documentfragment;
pub mod documenttype;
pub mod domexception;
pub mod domimplementation;
pub mod domparser;
pub mod dompoint;
pub mod dompointreadonly;
pub mod domquad;
pub mod domrect;
pub mod domrectlist;
pub mod domrectreadonly;
pub mod domstringmap;
pub mod domtokenlist;
pub mod element;
pub mod errorevent;
pub mod event;
pub mod eventdispatcher;
pub mod eventsource;
pub mod eventtarget;
pub mod file;
pub mod filelist;
pub mod filereader;
pub mod focusevent;
pub mod forcetouchevent;
pub mod formdata;
pub mod hashchangeevent;
pub mod htmlanchorelement;
pub mod htmlappletelement;
pub mod htmlareaelement;
pub mod htmlaudioelement;
pub mod htmlbaseelement;
pub mod htmlbodyelement;
pub mod htmlbrelement;
pub mod htmlbuttonelement;
pub mod htmlcanvaselement;
pub mod htmlcollection;
pub mod htmldataelement;
pub mod htmldatalistelement;
pub mod htmldetailselement;
pub mod htmldialogelement;
pub mod htmldirectoryelement;
pub mod htmldivelement;
pub mod htmldlistelement;
pub mod htmlelement;
pub mod htmlembedelement;
pub mod htmlfieldsetelement;
pub mod htmlfontelement;
pub mod htmlformcontrolscollection;
pub mod htmlformelement;
pub mod htmlframeelement;
pub mod htmlframesetelement;
pub mod htmlheadelement;
pub mod htmlheadingelement;
pub mod htmlhrelement;
pub mod htmlhtmlelement;
pub mod htmliframeelement;
pub mod htmlimageelement;
pub mod htmlinputelement;
pub mod htmllabelelement;
pub mod htmllegendelement;
pub mod htmllielement;
pub mod htmllinkelement;
pub mod htmlmapelement;
pub mod htmlmediaelement;
pub mod htmlmetaelement;
pub mod htmlmeterelement;
pub mod htmlmodelement;
pub mod htmlobjectelement;
pub mod htmlolistelement;
pub mod htmloptgroupelement;
pub mod htmloptionelement;
pub mod htmloutputelement;
pub mod htmlparagraphelement;
pub mod htmlparamelement;
pub mod htmlpreelement;
pub mod htmlprogresselement;
pub mod htmlquoteelement;
pub mod htmlscriptelement;
pub mod htmlselectelement;
pub mod htmlsourceelement;
pub mod htmlspanelement;
pub mod htmlstyleelement;
pub mod htmltablecaptionelement;
pub mod htmltablecellelement;
pub mod htmltablecolelement;
pub mod htmltabledatacellelement;
pub mod htmltableelement;
pub mod htmltableheadercellelement;
pub mod htmltablerowelement;
pub mod htmltablesectionelement;
pub mod htmltemplateelement;
pub mod htmltextareaelement;
pub mod htmltimeelement;
pub mod htmltitleelement;
pub mod htmltrackelement;
pub mod htmlulistelement;
pub mod htmlunknownelement;
pub mod htmlvideoelement;
pub mod imagedata;
pub mod keyboardevent;
pub mod location;
pub mod mediaerror;
pub mod messageevent;
pub mod mimetype;
pub mod mimetypearray;
pub mod mouseevent;
pub mod namednodemap;
pub mod navigator;
pub mod navigatorinfo;
pub mod node;
pub mod nodeiterator;
pub mod nodelist;
pub mod pagetransitionevent;
pub mod performance;
pub mod performancetiming;
pub mod plugin;
pub mod pluginarray;
pub mod popstateevent;
pub mod processinginstruction;
pub mod progressevent;
pub mod radionodelist;
pub mod range;
pub mod screen;
pub mod servohtmlparser;
pub mod servoxmlparser;
pub mod storage;
pub mod storageevent;
pub mod stylesheet;
pub mod stylesheetlist;
pub mod testbinding;
pub mod testbindingproxy;
pub mod text;
pub mod textdecoder;
pub mod textencoder;
pub mod touch;
pub mod touchevent;
pub mod touchlist;
pub mod treewalker;
pub mod uievent;
pub mod url;
pub mod urlhelper;
pub mod urlsearchparams;
pub mod userscripts;
pub mod validation;
pub mod validitystate;
pub mod values;
pub mod virtualmethods;
pub mod webglactiveinfo;
pub mod webglbuffer;
pub mod webglcontextevent;
pub mod webglframebuffer;
pub mod webglobject;
pub mod webglprogram;
pub mod webglrenderbuffer;
pub mod webglrenderingcontext;
pub mod webglshader;
pub mod webglshaderprecisionformat;
pub mod webgltexture;
pub mod webgluniformlocation;
pub mod websocket;
pub mod window;
pub mod worker;
pub mod workerglobalscope;
pub mod workerlocation;
pub mod workernavigator;
pub mod xmldocument;
pub mod xmlhttprequest;
pub mod xmlhttprequesteventtarget;
pub mod xmlhttprequestupload;
<|endoftext|>


<commit_before>/// Internal namespace.
pub( crate ) mod private
{
  use crate::prelude::*;

  macro_rules! NODE_ID
  {
    () => { < < Self as GraphNodesNominalInterface >::NodeHandle as HasId >::Id };
  }

  macro_rules! EDGE_ID
  {
    () => { < < Self as GraphEdgesNominalInterface >::EdgeHandle as HasId >::Id };
  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphNodesNominalInterface
  {

    /// Handle of a node - entity representing a node or the node itself.
    /// It's not always possible to operate a node directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise NodeHandle could be &Node.
    type NodeHandle : NodeBasicInterface;

    /// Convert argument into node id.
    #[ allow( non_snake_case ) ]
    #[ inline ]
    fn NodeId< Id >( id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    {
      id.into()
    }

    /// Convert argument into node id.
    #[ inline ]
    fn node_id< Id >( &self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    {
      id.into()
    }

    /// Get node with id.
    fn node< Id >( &self, id : Id ) -> &Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    // type OutNodesIteratorItem;
    // // type OutNodesIterator : Iterator< Item = ( &'it < Graph::NodeHandle as HasId >::Id, &'it Graph::NodeHandle ) >;
    // type OutNodesIterator : Iterator< Item = Self::OutNodesIteratorItem >;
    // /// Iterate over all nodes.
    // fn out_nodes_ids< Id >( &self, node_id : Id ) -> Self::OutNodesIterator
    // where
    //   Id : Into< NODE_ID!() >
    // ;

    /// Iterate over neighbourhood of the node. Callback gets ids of nodes in neighbourhood of a picked node.
    fn out_nodes_ids< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = NODE_ID!() > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    ;

    /// Iterate over neighbourhood of the node. Callback gets ids and reference on itself of nodes in neighbourhood of a picked node.
    fn out_nodes< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_nodes_ids( node_id ).map( | id |
      {
        ( id, self.node( id ) )
      }))
    }

  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphEdgesNominalInterface
  where
    Self : GraphNodesNominalInterface,
  {

    /// Handle of an edge - entity representing an edge or the edge itself.
    /// It's not always possible to operate an edge directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise EdgeHandle could be &Node.
    type EdgeHandle : EdgeBasicInterface;

    /// Convert argument into edge id.
    #[ allow( non_snake_case ) ]
    #[ inline ]
    fn EdgeId< Id >( id : Id ) -> EDGE_ID!()
    where
      Id : Into< EDGE_ID!() >
    {
      id.into()
    }

    /// Convert argument into edge id.
    #[ inline ]
    fn edge_id< Id >( &self, id : Id ) -> EDGE_ID!()
    where
      Id : Into< EDGE_ID!() >
    {
      Self::EdgeId( id )
    }

// xxx
//     /// Convert argument into edges ids.
//     #[ allow( non_snake_case ) ]
//     #[ inline ]
//     fn EdgesIds< In, Out >( src : In< EDGE_ID!() > ) -> Out< EDGE_ID!() >
//     where
//       In : IdsFromCollection,
//       Out : IdsCollection,
//     {
//       src.into()
//     }
//
//     /// Get edges with ids.
//     #[ inline ]
//     fn edges_ids< In, Out >( &self, src : In< EDGE_ID!() > ) -> Out< EDGE_ID!() >
//     where
//       In : IdsFromCollection,
//       Out : IdsCollection,
//     {
//       Self::EdgesIds( src )
//     }

    /// Get edge with id.
    fn edge< Id >( &self, id : Id ) -> &Self::EdgeHandle
    where
      Id : Into< EDGE_ID!() >
    ;

    /// Iterate over output edges of the node. Callback gets ids of nodes in neighbourhood of a picked node.
    fn out_edges_ids< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = EDGE_ID!() > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    ;

    /// Iterate over output edges of the node. Callback gets ids and references of edges in neighbourhood of a picked node.
    fn out_edges< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = ( EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_edges_ids( node_id ).map( | id |
      {
        ( id, self.edge( id ) )
      }))
    }

  }

  /// Into iterator of nodes.

  pub trait IntoIteratorOfNodes
  {
    type NodesIteratorItem;
    type NodesIterator : Iterator< Item = Self::NodesIteratorItem >;
    // /// Iterate over all nodes.
    // fn nodes( self ) -> Self::NodesIterator;
  }

  //

  impl< 'it, Graph > IntoIteratorOfNodes
  for &'it Graph
  where
    Graph : GraphNodesNominalInterface,
  {
    type NodesIteratorItem = ( &'it < Graph::NodeHandle as HasId >::Id, &'it Graph::NodeHandle );
    type NodesIterator = std::collections::hash_map::Iter< 'it, < Graph::NodeHandle as HasId >::Id, Graph::NodeHandle >;
    // fn nodes( self ) -> Self::NodesIterator
    // {
    //   self.map.iter()
    // }
  }

  ///
  /// Graph nodes of which is possible to enumerate.
  ///

  // pub trait GraphNodesEnumerableInterface< 'it, 'it2, It >
  pub trait GraphNodesEnumerableInterface
  where
    Self : GraphNodesNominalInterface,
    // It : Iterator< Item = &'it2 ( NODE_ID!(), &'it < Self as GraphNodesNominalInterface >::NodeHandle ) >,
    // < Self as GraphNodesNominalInterface >::NodeHandle : 'it,
    // 'it : 'it2,
  {

    // type NodesIteratorItem;
    // // type NodesIterator : Iterator< Item = ( &'it < Graph::NodeHandle as HasId >::Id, &'it Graph::NodeHandle ) >;
    // type NodesIterator : Iterator< Item = Self::NodesIteratorItem >;
    // /// Iterate over all nodes.
    // fn nodes( self ) -> Self::NodesIterator;

    /// Iterate over all nodes.
    fn nodes< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of nodes. Order of the graph.
    fn nnodes( &self ) -> usize
    {
      self.nodes().count()
    }

  }

  ///
  /// Graph edges of which is possible to enumerate.
  ///

  pub trait GraphEdgesEnumerableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {

    /// Iterate over all edges.
    fn edges< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of edges. Size of the graph.
    fn nedges( &self ) -> usize
    {
      self.edges().count()
    }

  }

  ///
  /// Graph interface which allow to add more nodes. Know nothing about edges.
  ///

  pub trait GraphNodesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
    ,
  {

    /// Get node with id mutably.
    fn node_mut< Id >( &mut self, id : Id ) -> &mut Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    /// Add out nodes to the node.
    fn node_add_out_nodes< IntoId1, IntoId2, Iter >
    (
      &mut self,
      node_id : IntoId1,
      out_nodes_iter : Iter,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId2 : Into< NODE_ID!() >,
      Iter : IntoIterator< Item = IntoId2 >,
      Iter::IntoIter : Clone,
    ;

    /// Add out edges to the node.
    fn node_add_out_node< IntoId1, IntoId2 >
    (
      &mut self,
      node_id : IntoId1,
      out_node_id : IntoId2,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId1 : Clone,
      IntoId2 : Into< NODE_ID!() >,
      IntoId2 : Clone,
    {
      self.node_add_out_nodes( node_id, core::iter::once( out_node_id ) );
    }

    /// Either make new or get existing node.
    fn node_making< Id >( &mut self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    ;

    /// Make edges.
    fn make_with_edge_list< IntoIter, Id >( &mut self, into_iter : IntoIter )
    where
      Id : Into< NODE_ID!() >,
      IntoIter : IntoIterator< Item = Id >,
      IntoIter::IntoIter : core::iter::ExactSizeIterator< Item = Id >,
    {
      use wtools::iter::prelude::*;
      let iter = into_iter.into_iter();
      debug_assert_eq!( iter.len() % 2, 0 );
      for mut chunk in &iter.chunks( 2 )
      {
        let id1 = chunk.next().unwrap().into();
        let id2 = chunk.next().unwrap().into();
        self.node_making( id1 );
        self.node_making( id2 );
        self.node_add_out_node( id1, id2 );
      }

    }

  }

  ///
  /// Graph interface which allow to add more edges.
  ///

  pub trait GraphEdgesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
      GraphNodesExtendableInterface +
    ,
  {

    /// Either make new or get existing edge for specified nodes.
    fn _edge_id_generate( &mut self, node1 : NODE_ID!(), node2 : NODE_ID!() ) -> EDGE_ID!();

    /// Either make new or get existing edge for specified nodes.
    fn _edge_add( &mut self, edge_id : EDGE_ID!(), node1 : NODE_ID!(), node2 : NODE_ID!() );

    /// Either make new or get existing edge for specified nodes.
    fn _edge_make_for_nodes< IntoNodeId1, IntoNodeId2 >( &mut self, node1 : IntoNodeId1, node2 : IntoNodeId2 ) -> EDGE_ID!()
    where
      IntoNodeId1 : Into< NODE_ID!() >,
      IntoNodeId2 : Into< NODE_ID!() >,
    {
      let node1 = node1.into();
      let node2 = node2.into();
      let edge = self._edge_id_generate( node1, node2 );
      self._edge_add( edge, node1, node2 );
      edge
    }

  }

  ///
  /// Graph nodes of which has a kind.
  ///

  pub trait GraphNodesKindGetterInterface
  where
    Self : GraphNodesNominalInterface,
  {
    /// Enumerate kinds of the node.
    type NodeKind : crate::NodeKindInterface;
    /// Get kind of the node.
    fn node_kind( &self, node_id : NODE_ID!() ) -> Self::NodeKind;
  }

  ///
  /// Graph nodes of which has a kind.
  ///

  pub trait GraphEdgesKindGetterInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {
    /// Enumerate kinds of the node.
    type EdgeKind : crate::EdgeKindInterface;
    /// Get kind of the node.
    fn edge_kind( &self, edge_id : EDGE_ID!() ) -> Self::EdgeKind;
  }

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;
}

pub use protected::*;

/// Parented namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

pub use exposed::*;

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
  pub use super::private::
  {
    GraphNodesNominalInterface,
    GraphEdgesNominalInterface,
    GraphNodesEnumerableInterface,
    GraphEdgesEnumerableInterface,
    GraphNodesExtendableInterface,
    GraphEdgesExtendableInterface,
    GraphNodesKindGetterInterface,
    GraphEdgesKindGetterInterface,
  };
}
<commit_msg>graphs : switch off cell factortory<commit_after>/// Internal namespace.
pub( crate ) mod private
{
  use crate::prelude::*;

  macro_rules! NODE_ID
  {
    () => { < < Self as GraphNodesNominalInterface >::NodeHandle as HasId >::Id };
  }

  macro_rules! EDGE_ID
  {
    () => { < < Self as GraphEdgesNominalInterface >::EdgeHandle as HasId >::Id };
  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphNodesNominalInterface
  {

    /// Handle of a node - entity representing a node or the node itself.
    /// It's not always possible to operate a node directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise NodeHandle could be &Node.
    type NodeHandle : NodeBasicInterface;

    /// Convert argument into node id.
    #[ allow( non_snake_case ) ]
    #[ inline ]
    fn NodeId< Id >( id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    {
      id.into()
    }

    /// Convert argument into node id.
    #[ inline ]
    fn node_id< Id >( &self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    {
      id.into()
    }

    /// Get node with id.
    fn node< Id >( &self, id : Id ) -> &Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    // type OutNodesIteratorItem;
    // // type OutNodesIterator : Iterator< Item = ( &'it < Graph::NodeHandle as HasId >::Id, &'it Graph::NodeHandle ) >;
    // type OutNodesIterator : Iterator< Item = Self::OutNodesIteratorItem >;
    // /// Iterate over all nodes.
    // fn out_nodes_ids< Id >( &self, node_id : Id ) -> Self::OutNodesIterator
    // where
    //   Id : Into< NODE_ID!() >
    // ;

    /// Iterate over neighbourhood of the node. Callback gets ids of nodes in neighbourhood of a picked node.
    fn out_nodes_ids< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = NODE_ID!() > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    ;

    /// Iterate over neighbourhood of the node. Callback gets ids and reference on itself of nodes in neighbourhood of a picked node.
    fn out_nodes< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_nodes_ids( node_id ).map( | id |
      {
        ( id, self.node( id ) )
      }))
    }

  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphEdgesNominalInterface
  where
    Self : GraphNodesNominalInterface,
  {

    /// Handle of an edge - entity representing an edge or the edge itself.
    /// It's not always possible to operate an edge directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise EdgeHandle could be &Node.
    type EdgeHandle : EdgeBasicInterface;

    /// Convert argument into edge id.
    #[ allow( non_snake_case ) ]
    #[ inline ]
    fn EdgeId< Id >( id : Id ) -> EDGE_ID!()
    where
      Id : Into< EDGE_ID!() >
    {
      id.into()
    }

    /// Convert argument into edge id.
    #[ inline ]
    fn edge_id< Id >( &self, id : Id ) -> EDGE_ID!()
    where
      Id : Into< EDGE_ID!() >
    {
      Self::EdgeId( id )
    }

// xxx
//     /// Convert argument into edges ids.
//     #[ allow( non_snake_case ) ]
//     #[ inline ]
//     fn EdgesIds< In, Out >( src : In< EDGE_ID!() > ) -> Out< EDGE_ID!() >
//     where
//       In : IdsFromCollection,
//       Out : IdsCollection,
//     {
//       src.into()
//     }
//
//     /// Get edges with ids.
//     #[ inline ]
//     fn edges_ids< In, Out >( &self, src : In< EDGE_ID!() > ) -> Out< EDGE_ID!() >
//     where
//       In : IdsFromCollection,
//       Out : IdsCollection,
//     {
//       Self::EdgesIds( src )
//     }

    /// Get edge with id.
    fn edge< Id >( &self, id : Id ) -> &Self::EdgeHandle
    where
      Id : Into< EDGE_ID!() >
    ;

    /// Iterate over output edges of the node. Callback gets ids of nodes in neighbourhood of a picked node.
    fn out_edges_ids< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = EDGE_ID!() > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    ;

    /// Iterate over output edges of the node. Callback gets ids and references of edges in neighbourhood of a picked node.
    fn out_edges< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = ( EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_edges_ids( node_id ).map( | id |
      {
        ( id, self.edge( id ) )
      }))
    }

  }

//   /// Into iterator of nodes.
//
//   pub trait IntoIteratorOfNodes
//   {
//     type NodesIteratorItem;
//     type NodesIterator : Iterator< Item = Self::NodesIteratorItem >;
//     // /// Iterate over all nodes.
//     // fn nodes( self ) -> Self::NodesIterator;
//   }
//
//   //
//
//   impl< 'it, Graph > IntoIteratorOfNodes
//   for &'it Graph
//   where
//     Graph : GraphNodesNominalInterface,
//   {
//     type NodesIteratorItem = ( &'it < Graph::NodeHandle as HasId >::Id, &'it Graph::NodeHandle );
//     type NodesIterator = std::collections::hash_map::Iter< 'it, < Graph::NodeHandle as HasId >::Id, Graph::NodeHandle >;
//     // fn nodes( self ) -> Self::NodesIterator
//     // {
//     //   self.map.iter()
//     // }
//   }

  ///
  /// Graph nodes of which is possible to enumerate.
  ///

  // pub trait GraphNodesEnumerableInterface< 'it, 'it2, It >
  pub trait GraphNodesEnumerableInterface
  where
    Self : GraphNodesNominalInterface,
    // It : Iterator< Item = &'it2 ( NODE_ID!(), &'it < Self as GraphNodesNominalInterface >::NodeHandle ) >,
    // < Self as GraphNodesNominalInterface >::NodeHandle : 'it,
    // 'it : 'it2,
  {

    // type NodesIteratorItem;
    // // type NodesIterator : Iterator< Item = ( &'it < Graph::NodeHandle as HasId >::Id, &'it Graph::NodeHandle ) >;
    // type NodesIterator : Iterator< Item = Self::NodesIteratorItem >;
    // /// Iterate over all nodes.
    // fn nodes( self ) -> Self::NodesIterator;

    /// Iterate over all nodes.
    fn nodes< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of nodes. Order of the graph.
    fn nnodes( &self ) -> usize
    {
      self.nodes().count()
    }

  }

  ///
  /// Graph edges of which is possible to enumerate.
  ///

  pub trait GraphEdgesEnumerableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {

    /// Iterate over all edges.
    fn edges< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of edges. Size of the graph.
    fn nedges( &self ) -> usize
    {
      self.edges().count()
    }

  }

  ///
  /// Graph interface which allow to add more nodes. Know nothing about edges.
  ///

  pub trait GraphNodesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
    ,
  {

    /// Get node with id mutably.
    fn node_mut< Id >( &mut self, id : Id ) -> &mut Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    /// Add out nodes to the node.
    fn node_add_out_nodes< IntoId1, IntoId2, Iter >
    (
      &mut self,
      node_id : IntoId1,
      out_nodes_iter : Iter,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId2 : Into< NODE_ID!() >,
      Iter : IntoIterator< Item = IntoId2 >,
      Iter::IntoIter : Clone,
    ;

    /// Add out edges to the node.
    fn node_add_out_node< IntoId1, IntoId2 >
    (
      &mut self,
      node_id : IntoId1,
      out_node_id : IntoId2,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId1 : Clone,
      IntoId2 : Into< NODE_ID!() >,
      IntoId2 : Clone,
    {
      self.node_add_out_nodes( node_id, core::iter::once( out_node_id ) );
    }

    /// Either make new or get existing node.
    fn node_making< Id >( &mut self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    ;

    /// Make edges.
    fn make_with_edge_list< IntoIter, Id >( &mut self, into_iter : IntoIter )
    where
      Id : Into< NODE_ID!() >,
      IntoIter : IntoIterator< Item = Id >,
      IntoIter::IntoIter : core::iter::ExactSizeIterator< Item = Id >,
    {
      use wtools::iter::prelude::*;
      let iter = into_iter.into_iter();
      debug_assert_eq!( iter.len() % 2, 0 );
      for mut chunk in &iter.chunks( 2 )
      {
        let id1 = chunk.next().unwrap().into();
        let id2 = chunk.next().unwrap().into();
        self.node_making( id1 );
        self.node_making( id2 );
        self.node_add_out_node( id1, id2 );
      }

    }

  }

  ///
  /// Graph interface which allow to add more edges.
  ///

  pub trait GraphEdgesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
      GraphNodesExtendableInterface +
    ,
  {

    /// Either make new or get existing edge for specified nodes.
    fn _edge_id_generate( &mut self, node1 : NODE_ID!(), node2 : NODE_ID!() ) -> EDGE_ID!();

    /// Either make new or get existing edge for specified nodes.
    fn _edge_add( &mut self, edge_id : EDGE_ID!(), node1 : NODE_ID!(), node2 : NODE_ID!() );

    /// Either make new or get existing edge for specified nodes.
    fn _edge_make_for_nodes< IntoNodeId1, IntoNodeId2 >( &mut self, node1 : IntoNodeId1, node2 : IntoNodeId2 ) -> EDGE_ID!()
    where
      IntoNodeId1 : Into< NODE_ID!() >,
      IntoNodeId2 : Into< NODE_ID!() >,
    {
      let node1 = node1.into();
      let node2 = node2.into();
      let edge = self._edge_id_generate( node1, node2 );
      self._edge_add( edge, node1, node2 );
      edge
    }

  }

  ///
  /// Graph nodes of which has a kind.
  ///

  pub trait GraphNodesKindGetterInterface
  where
    Self : GraphNodesNominalInterface,
  {
    /// Enumerate kinds of the node.
    type NodeKind : crate::NodeKindInterface;
    /// Get kind of the node.
    fn node_kind( &self, node_id : NODE_ID!() ) -> Self::NodeKind;
  }

  ///
  /// Graph nodes of which has a kind.
  ///

  pub trait GraphEdgesKindGetterInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {
    /// Enumerate kinds of the node.
    type EdgeKind : crate::EdgeKindInterface;
    /// Get kind of the node.
    fn edge_kind( &self, edge_id : EDGE_ID!() ) -> Self::EdgeKind;
  }

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;
}

pub use protected::*;

/// Parented namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

pub use exposed::*;

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
  pub use super::private::
  {
    GraphNodesNominalInterface,
    GraphEdgesNominalInterface,
    GraphNodesEnumerableInterface,
    GraphEdgesEnumerableInterface,
    GraphNodesExtendableInterface,
    GraphEdgesExtendableInterface,
    GraphNodesKindGetterInterface,
    GraphEdgesKindGetterInterface,
  };
}
<|endoftext|>


<commit_before>///! Property-based testing strategies
use itertools::interleave;
use proptest::collection::{size_range, vec};
use proptest::prelude::*;
use proptest::strategy::Union;
use stencila_schema::{
    Article, AudioObjectSimple, BlockContent, CodeBlock, CodeFragment, Emphasis, Heading,
    ImageObjectSimple, InlineContent, Link, List, ListItem, ListItemContent, ListOrder, Node,
    Paragraph, Strong, ThematicBreak, VideoObjectSimple,
};

/// The degree of freedom when generating arbitrary nodes.
///
/// Generally, when adding a `proptest` it is wise to start with `Nil`
/// freedom and gradually increase it while fixing issues along the way.
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum Freedom {
    Nil,
    Low,
    High,
}

prop_compose! {
    /// Generate an arbitrary inline string
    pub fn string(freedom: Freedom)(
        string in (match freedom {
            Freedom::Nil => r"string",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }).prop_filter(
            "Inline strings should not be empty",
            |string| !string.is_empty()
        )
    ) -> InlineContent {
        InlineContent::String(string)
    }
}

prop_compose! {
    /// Generate an arbitrary audio object
    pub fn audio_object_simple(freedom: Freedom)(
        content_url in match freedom {
            Freedom::Nil => r"url",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        InlineContent::AudioObject(AudioObjectSimple{
            content_url,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate an arbitrary image object
    pub fn image_object_simple(freedom: Freedom)(
        content_url in match freedom {
            Freedom::Nil => r"url",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        InlineContent::ImageObject(ImageObjectSimple{
            content_url,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate an arbitrary video object
    pub fn video_object_simple(freedom: Freedom)(
        content_url in match freedom {
            Freedom::Nil => r"url",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        InlineContent::VideoObject(VideoObjectSimple{
            content_url,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a code fragment node with arbitrary text and programming language
    pub fn code_fragment(freedom: Freedom)(
        text in match freedom {
            Freedom::Nil => r"text",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        },
        programming_language in match freedom {
            Freedom::Nil => r"lang",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        let programming_language = if programming_language.is_empty() {
            None
        } else {
            Some(Box::new(programming_language))
        };
        InlineContent::CodeFragment(CodeFragment{
            text,
            programming_language,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a emphasis node with arbitrary content
    pub fn emphasis(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Emphasis(Emphasis{
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a strong node with arbitrary content
    pub fn strong(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Strong(Strong{
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a link with arbitrary target and content
    pub fn link(freedom: Freedom)(
        target in match freedom {
            Freedom::Nil => r"target",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        },
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Link(Link{
            target,
            content:vec![content],
            ..Default::default()
        })
    }
}

/// Generate one of the inline content node types excluding strings (which
/// we usually want to be interleaved between them).
pub fn inline_content(freedom: Freedom) -> impl Strategy<Value = InlineContent> {
    Union::new(vec![
        audio_object_simple(freedom).boxed(),
        image_object_simple(freedom).boxed(),
        video_object_simple(freedom).boxed(),
        code_fragment(freedom).boxed(),
        emphasis(freedom).boxed(),
        strong(freedom).boxed(),
        link(freedom).boxed(),
    ])
}

prop_compose! {
    /// Generate a vector of inline content of arbitrary length and content
    /// but always having strings interspersed by other inline content (to separate them).
    pub fn vec_inline_content(freedom: Freedom)(length in 1usize..10)(
        strings in vec(string(freedom), size_range(length)),
        others in vec(inline_content(freedom), size_range(length))
    ) -> Vec<InlineContent> {
        interleave(strings, others).collect()
    }
}

prop_compose! {
    /// Generate a code block node with arbitrary text and programming language
    pub fn code_block(freedom: Freedom)(
        text in match freedom {
            Freedom::Nil => r"text",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        },
        programming_language in match freedom {
            Freedom::Nil => r"lang",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> BlockContent {
        let programming_language = if programming_language.is_empty() {
            None
        } else {
            Some(Box::new(programming_language))
        };
        BlockContent::CodeBlock(CodeBlock{
            text,
            programming_language,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a heading with arbitrary content and depth
    pub fn heading(freedom: Freedom)(
        depth in 1..6,
        content in vec_inline_content(freedom)
    ) -> BlockContent {
        BlockContent::Heading(Heading{
            depth: Some(Box::new(depth as i64)),
            content,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a paragraph with arbitrary content
    pub fn paragraph(freedom: Freedom)(
        content in vec_inline_content(freedom)
    ) -> BlockContent {
        BlockContent::Paragraph(Paragraph{
            content,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a list with arbitrary items and order
    pub fn list(freedom: Freedom)(
        order in prop_oneof![Just(ListOrder::Ascending), Just(ListOrder::Unordered)],
        items in vec(list_item(freedom), 1..5)
    ) -> BlockContent {
        BlockContent::List(List{
            order: Some(Box::new(order)),
            items,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a list item with arbitrary inline content.
    /// Unable to use block_content here because that causes infinite recursion
    pub fn list_item(freedom: Freedom)(
        content in vec(inline_content(freedom), 1..3)
    ) -> ListItem {
        ListItem{
            content: Some(Box::new(ListItemContent::VecInlineContent(content))),
            ..Default::default()
        }
    }
}

/// Generate a thematic break
pub fn thematic_break() -> impl Strategy<Value = BlockContent> {
    Just(BlockContent::ThematicBreak(ThematicBreak::default()))
}

/// Generate one of the block content node types
pub fn block_content(freedom: Freedom) -> impl Strategy<Value = BlockContent> {
    Union::new(vec![
        code_block(freedom).boxed(),
        heading(freedom).boxed(),
        list(freedom).boxed(),
        paragraph(freedom).boxed(),
        thematic_break().boxed(),
    ])
}

prop_compose! {
    /// Generate an article with arbitrary content (and in the future, other properties)
    pub fn article(freedom: Freedom)(
        content in vec(block_content(freedom), 1..10)
    ) -> Node {
        Node::Article(Article{content: Some(content), ..Default::default()})
    }
}

/// Generate an arbitrary node
pub fn node(freedom: Freedom) -> impl Strategy<Value = Node> {
    Union::new(vec![article(freedom).boxed()])
}
<commit_msg>test(*): Add more inline content to strategies<commit_after>///! Property-based testing strategies
use itertools::interleave;
use proptest::collection::{size_range, vec};
use proptest::prelude::*;
use proptest::strategy::Union;
use stencila_schema::*;

/// The degree of freedom when generating arbitrary nodes.
///
/// Generally, when adding a `proptest` it is wise to start with `Nil`
/// freedom and gradually increase it while fixing issues along the way.
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum Freedom {
    Nil,
    Low,
    High,
}

prop_compose! {
    /// Generate an arbitrary inline string
    pub fn string(freedom: Freedom)(
        string in (match freedom {
            Freedom::Nil => r"string",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }).prop_filter(
            "Inline strings should not be empty",
            |string| !string.is_empty()
        )
    ) -> InlineContent {
        InlineContent::String(string)
    }
}

prop_compose! {
    /// Generate an arbitrary audio object
    pub fn audio_object_simple(freedom: Freedom)(
        content_url in match freedom {
            Freedom::Nil => r"url",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        InlineContent::AudioObject(AudioObjectSimple{
            content_url,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate an arbitrary image object
    pub fn image_object_simple(freedom: Freedom)(
        content_url in match freedom {
            Freedom::Nil => r"url",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        InlineContent::ImageObject(ImageObjectSimple{
            content_url,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate an arbitrary video object
    pub fn video_object_simple(freedom: Freedom)(
        content_url in match freedom {
            Freedom::Nil => r"url",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        InlineContent::VideoObject(VideoObjectSimple{
            content_url,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a code fragment node with arbitrary text and programming language
    pub fn code_fragment(freedom: Freedom)(
        text in match freedom {
            Freedom::Nil => r"text",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        },
        programming_language in match freedom {
            Freedom::Nil => r"lang",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> InlineContent {
        let programming_language = if programming_language.is_empty() {
            None
        } else {
            Some(Box::new(programming_language))
        };
        InlineContent::CodeFragment(CodeFragment{
            text,
            programming_language,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a delete node with arbitrary content
    pub fn delete(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Delete(Delete{
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a emphasis node with arbitrary content
    pub fn emphasis(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Emphasis(Emphasis{
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a link with arbitrary target and content
    pub fn link(freedom: Freedom)(
        target in match freedom {
            Freedom::Nil => r"target",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        },
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Link(Link{
            target,
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a nontextual annotation node with arbitrary content
    pub fn nontextual_annotation(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::NontextualAnnotation(NontextualAnnotation{
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a strong node with arbitrary content
    pub fn strong(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Strong(Strong{
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a subscript node with arbitrary content
    pub fn subscript(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Subscript(Subscript{
            content:vec![content],
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a superscript node with arbitrary content
    pub fn superscript(freedom: Freedom)(
        content in string(freedom)
    ) -> InlineContent {
        InlineContent::Superscript(Superscript{
            content:vec![content],
            ..Default::default()
        })
    }
}

/// Generate one of the inline content node types excluding strings (which
/// we usually want to be interleaved between them).
pub fn inline_content(freedom: Freedom) -> impl Strategy<Value = InlineContent> {
    Union::new(vec![
        audio_object_simple(freedom).boxed(),
        image_object_simple(freedom).boxed(),
        video_object_simple(freedom).boxed(),
        code_fragment(freedom).boxed(),
        delete(freedom).boxed(),
        emphasis(freedom).boxed(),
        link(freedom).boxed(),
        nontextual_annotation(freedom).boxed(),
        strong(freedom).boxed(),
        subscript(freedom).boxed(),
        superscript(freedom).boxed(),
    ])
}

prop_compose! {
    /// Generate a vector of inline content of arbitrary length and content
    /// but always having strings interspersed by other inline content (to separate them).
    pub fn vec_inline_content(freedom: Freedom)(length in 1usize..10)(
        strings in vec(string(freedom), size_range(length)),
        others in vec(inline_content(freedom), size_range(length))
    ) -> Vec<InlineContent> {
        interleave(strings, others).collect()
    }
}

prop_compose! {
    /// Generate a code block node with arbitrary text and programming language
    pub fn code_block(freedom: Freedom)(
        text in match freedom {
            Freedom::Nil => r"text",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        },
        programming_language in match freedom {
            Freedom::Nil => r"lang",
            Freedom::Low => r"[a-zA-Z0-9 \t\n]+",
            Freedom::High => any::<String>()
        }
    ) -> BlockContent {
        let programming_language = if programming_language.is_empty() {
            None
        } else {
            Some(Box::new(programming_language))
        };
        BlockContent::CodeBlock(CodeBlock{
            text,
            programming_language,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a heading with arbitrary content and depth
    pub fn heading(freedom: Freedom)(
        depth in 1..6,
        content in vec_inline_content(freedom)
    ) -> BlockContent {
        BlockContent::Heading(Heading{
            depth: Some(Box::new(depth as i64)),
            content,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a paragraph with arbitrary content
    pub fn paragraph(freedom: Freedom)(
        content in vec_inline_content(freedom)
    ) -> BlockContent {
        BlockContent::Paragraph(Paragraph{
            content,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a list with arbitrary items and order
    pub fn list(freedom: Freedom)(
        order in prop_oneof![Just(ListOrder::Ascending), Just(ListOrder::Unordered)],
        items in vec(list_item(freedom), 1..5)
    ) -> BlockContent {
        BlockContent::List(List{
            order: Some(Box::new(order)),
            items,
            ..Default::default()
        })
    }
}

prop_compose! {
    /// Generate a list item with arbitrary inline content.
    /// Unable to use block_content here because that causes infinite recursion
    pub fn list_item(freedom: Freedom)(
        content in vec(inline_content(freedom), 1..3)
    ) -> ListItem {
        ListItem{
            content: Some(Box::new(ListItemContent::VecInlineContent(content))),
            ..Default::default()
        }
    }
}

/// Generate a thematic break
pub fn thematic_break() -> impl Strategy<Value = BlockContent> {
    Just(BlockContent::ThematicBreak(ThematicBreak::default()))
}

/// Generate one of the block content node types
pub fn block_content(freedom: Freedom) -> impl Strategy<Value = BlockContent> {
    Union::new(vec![
        code_block(freedom).boxed(),
        heading(freedom).boxed(),
        list(freedom).boxed(),
        paragraph(freedom).boxed(),
        thematic_break().boxed(),
    ])
}

prop_compose! {
    /// Generate an article with arbitrary content (and in the future, other properties)
    pub fn article(freedom: Freedom)(
        content in vec(block_content(freedom), 1..10)
    ) -> Node {
        Node::Article(Article{content: Some(content), ..Default::default()})
    }
}

/// Generate an arbitrary node
pub fn node(freedom: Freedom) -> impl Strategy<Value = Node> {
    Union::new(vec![article(freedom).boxed()])
}
<|endoftext|>


<commit_before>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("%s: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.2",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use core::io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum ParseType {
    FieldLabel,
    FieldValue,
    Field,
    Record,
    Ltsv
}

#[deriving_eq]
enum ParseDelimiter {
    EOF, TAB, NL, MISC
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, ParseDelimiter, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool);
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool);
}

impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_ltsv() {
            ParseError(reason) => fail!(reason),
            ParseOk(_, _, records) => records
        }
    }
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_record() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, record) => if !f(&record) { break; }
            }
        }
    }
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_field() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, field) => if !f(&field) { break; }
            }
        }
    }
}

struct LTSVParser<T> {
    priv rd: &'self T,
    priv cur: @mut int
}

pub impl<T: io::Reader> LTSVParser<'self, T> {
    fn new(rd: &'r T) -> LTSVParser/&r<T> {
        let cur = @mut rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn eof(&self) -> bool { *self.cur == -1 }

    fn bump(&self) {
        if !self.eof() {
            *self.cur = self.rd.read_byte();
        }
    }

    fn parse_ltsv(&self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_record() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, EOF, record) => {
                    records.push(record);
                    break;
                }
                ParseOk(_, _, record) => {
                    records.push(record);
                }
            }
        }
        ParseOk(Ltsv, EOF, records)
    }

    fn parse_record(&self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        loop {
            match self.parse_field() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, TAB, (label, value)) => {
                    record.insert(label, value);
                }
                ParseOk(_, delim, (label, value)) => {
                    record.insert(label, value);
                    return ParseOk(Record, delim, record);
                }
            }
        }
    }

    fn parse_field(&self) -> ParseResult<(~str, ~str)> {
        self.skip_whitespaces();
        let label = match self.parse_field_label() {
            ParseError(reason) => return ParseError(reason),
            ParseOk(_, _, label) => { self.bump(); label }
        };
        match self.parse_field_value() {
            ParseError(reason) => {
                ParseError(reason)
            }
            ParseOk(_, delim, value) => {
                self.bump();
                // avoid skipping whitespaces in the middle of parsing record.
                if delim != TAB { self.skip_whitespaces(); }
                // re-check EOF
                let delim = if self.eof() { EOF } else { delim };
                ParseOk(Field, delim, (label, value))
            }
        }
    }

    priv fn parse_field_label(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match *self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(*self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, MISC, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn parse_field_value(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match *self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(*self.cur as u8),
                0x0d => return self.consume_forward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue, NL, str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue, TAB, str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue, EOF, str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn consume_forward_LF(&self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if *self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue, NL, rv)
        }
    }

    priv fn skip_whitespaces(&self) {
        while char::is_whitespace(*self.cur as char) {
            self.bump();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::io::WriterUtil;

    fn mk_record_string() -> ~str {
        do io::with_str_writer |wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        }
    }

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert_eq!(records.len(), 1);
    }

    #[test]
    fn test_parse_full() {
        let s = mk_record_string();
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert_eq!(records.len(), 2);
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = mk_record_string();
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert_eq!(records_1, records_2);
    }

    #[test]
    fn test_each_read_each_record() {
        let s = mk_record_string();
        let ks = [~"tofu", ~"kamaboko", ~"sukonbu"];
        let vs = [~"豆", ~"魚", ~"海藻", ~"好き", ~"普通", ~"苦手"];
        do io::with_str_reader(s) |rd| {
            for rd.each_ltsv_record |record| {
                for record.each |&(k, v)| {
                    assert!(ks.contains(k));
                    assert!(vs.contains(v));
                }
            }
        }
    }
}
<commit_msg>Update for language changes<commit_after>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("%s: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.2",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use core::io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum ParseType {
    FieldLabel,
    FieldValue,
    Field,
    Record,
    Ltsv
}

#[deriving(Eq)]
enum ParseDelimiter {
    EOF, TAB, NL, MISC
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, ParseDelimiter, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool);
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool);
}

impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_ltsv() {
            ParseError(reason) => fail!(reason),
            ParseOk(_, _, records) => records
        }
    }
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_record() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, record) => if !f(&record) { break; }
            }
        }
    }
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_field() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, field) => if !f(&field) { break; }
            }
        }
    }
}

struct LTSVParser<'self, T> {
    priv rd: &'self T,
    priv cur: @mut int
}

pub impl<'self, T: io::Reader> LTSVParser<'self, T> {
    fn new(rd: &'self T) -> LTSVParser<'self, T> {
        let cur = @mut rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn eof(&self) -> bool { *self.cur == -1 }

    fn bump(&self) {
        if !self.eof() {
            *self.cur = self.rd.read_byte();
        }
    }

    fn parse_ltsv(&self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_record() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, EOF, record) => {
                    records.push(record);
                    break;
                }
                ParseOk(_, _, record) => {
                    records.push(record);
                }
            }
        }
        ParseOk(Ltsv, EOF, records)
    }

    fn parse_record(&self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        loop {
            match self.parse_field() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, TAB, (label, value)) => {
                    record.insert(label, value);
                }
                ParseOk(_, delim, (label, value)) => {
                    record.insert(label, value);
                    return ParseOk(Record, delim, record);
                }
            }
        }
    }

    fn parse_field(&self) -> ParseResult<(~str, ~str)> {
        self.skip_whitespaces();
        let label = match self.parse_field_label() {
            ParseError(reason) => return ParseError(reason),
            ParseOk(_, _, label) => { self.bump(); label }
        };
        match self.parse_field_value() {
            ParseError(reason) => {
                ParseError(reason)
            }
            ParseOk(_, delim, value) => {
                self.bump();
                // avoid skipping whitespaces in the middle of parsing record.
                if delim != TAB { self.skip_whitespaces(); }
                // re-check EOF
                let delim = if self.eof() { EOF } else { delim };
                ParseOk(Field, delim, (label, value))
            }
        }
    }

    priv fn parse_field_label(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match *self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(*self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, MISC, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn parse_field_value(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match *self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(*self.cur as u8),
                0x0d => return self.consume_forward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue, NL, str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue, TAB, str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue, EOF, str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn consume_forward_LF(&self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if *self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue, NL, rv)
        }
    }

    priv fn skip_whitespaces(&self) {
        while char::is_whitespace(*self.cur as char) {
            self.bump();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::io::WriterUtil;

    fn mk_record_string() -> ~str {
        do io::with_str_writer |wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        }
    }

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert_eq!(records.len(), 1);
    }

    #[test]
    fn test_parse_full() {
        let s = mk_record_string();
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert_eq!(records.len(), 2);
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = mk_record_string();
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert_eq!(records_1, records_2);
    }

    #[test]
    fn test_each_read_each_record() {
        let s = mk_record_string();
        let ks = [~"tofu", ~"kamaboko", ~"sukonbu"];
        let vs = [~"豆", ~"魚", ~"海藻", ~"好き", ~"普通", ~"苦手"];
        do io::with_str_reader(s) |rd| {
            for rd.each_ltsv_record |record| {
                for record.each |&(k, v)| {
                    assert!(ks.contains(k));
                    assert!(vs.contains(v));
                }
            }
        }
    }
}
<|endoftext|>