@@ -342,6 +342,51 @@ impl fmt::Display for IndexItemFunctionType {
342342thread_local ! ( static CACHE_KEY : RefCell <Arc <Cache >> = Default :: default ( ) ) ;
343343thread_local ! ( pub static CURRENT_LOCATION_KEY : RefCell <Vec <String >> =
344344 RefCell :: new( Vec :: new( ) ) ) ;
345+ thread_local ! ( static USED_ID_MAP : RefCell <HashMap <String , usize >> =
346+ RefCell :: new( init_ids( ) ) ) ;
347+
348+ fn init_ids ( ) -> HashMap < String , usize > {
349+ [
350+ "main" ,
351+ "search" ,
352+ "help" ,
353+ "TOC" ,
354+ "render-detail" ,
355+ "associated-types" ,
356+ "associated-const" ,
357+ "required-methods" ,
358+ "provided-methods" ,
359+ "implementors" ,
360+ "implementors-list" ,
361+ "methods" ,
362+ "deref-methods" ,
363+ "implementations" ,
364+ "derived_implementations"
365+ ] . into_iter ( ) . map ( |id| ( String :: from ( * id) , 1 ) ) . collect :: < HashMap < _ , _ > > ( )
366+ }
367+
368+ /// This method resets the local table of used ID attributes. This is typically
369+ /// used at the beginning of rendering an entire HTML page to reset from the
370+ /// previous state (if any).
371+ pub fn reset_ids ( ) {
372+ USED_ID_MAP . with ( |s| * s. borrow_mut ( ) = init_ids ( ) ) ;
373+ }
374+
375+ pub fn derive_id ( candidate : String ) -> String {
376+ USED_ID_MAP . with ( |map| {
377+ let id = match map. borrow_mut ( ) . get_mut ( & candidate) {
378+ None => candidate,
379+ Some ( a) => {
380+ let id = format ! ( "{}-{}" , candidate, * a) ;
381+ * a += 1 ;
382+ id
383+ }
384+ } ;
385+
386+ map. borrow_mut ( ) . insert ( id. clone ( ) , 1 ) ;
387+ id
388+ } )
389+ }
345390
346391/// Generates the documentation for `crate` into the directory `dst`
347392pub fn run ( mut krate : clean:: Crate ,
@@ -1276,7 +1321,7 @@ impl Context {
12761321 keywords : & keywords,
12771322 } ;
12781323
1279- markdown :: reset_headers ( ) ;
1324+ reset_ids ( ) ;
12801325
12811326 // We have a huge number of calls to write, so try to alleviate some
12821327 // of the pain by using a buffered writer instead of invoking the
@@ -1698,10 +1743,9 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
16981743 ItemType :: AssociatedType => ( "associated-types" , "Associated Types" ) ,
16991744 ItemType :: AssociatedConst => ( "associated-consts" , "Associated Constants" ) ,
17001745 } ;
1701- try!( write ! ( w,
1702- "<h2 id='{id}' class='section-header'>\
1703- <a href=\" #{id}\" >{name}</a></h2>\n <table>",
1704- id = short, name = name) ) ;
1746+ try!( write ! ( w, "<h2 id='{id}' class='section-header'>\
1747+ <a href=\" #{id}\" >{name}</a></h2>\n <table>",
1748+ id = derive_id( short. to_owned( ) ) , name = name) ) ;
17051749 }
17061750
17071751 match myitem. inner {
@@ -1922,10 +1966,11 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
19221966
19231967 fn trait_item ( w : & mut fmt:: Formatter , cx : & Context , m : & clean:: Item )
19241968 -> fmt:: Result {
1925- try!( write ! ( w, "<h3 id='{ty}.{name}' class='method stab {stab}'><code>" ,
1926- ty = shortty( m) ,
1927- name = * m. name. as_ref( ) . unwrap( ) ,
1928- stab = m. stability_class( ) ) ) ;
1969+ let name = m. name . as_ref ( ) . unwrap ( ) ;
1970+ let id = derive_id ( format ! ( "{}.{}" , shortty( m) , name) ) ;
1971+ try!( write ! ( w, "<h3 id='{id}' class='method stab {stab}'><code>" ,
1972+ id = id,
1973+ stab = m. stability_class( ) ) ) ;
19291974 try!( render_assoc_item ( w, m, AssocItemLink :: Anchor ) ) ;
19301975 try!( write ! ( w, "</code></h3>" ) ) ;
19311976 try!( document ( w, cx, m) ) ;
@@ -2420,44 +2465,38 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
24202465
24212466 fn doctraititem ( w : & mut fmt:: Formatter , cx : & Context , item : & clean:: Item ,
24222467 link : AssocItemLink , render_static : bool ) -> fmt:: Result {
2468+ let name = item. name . as_ref ( ) . unwrap ( ) ;
24232469 match item. inner {
24242470 clean:: MethodItem ( ..) | clean:: TyMethodItem ( ..) => {
24252471 // Only render when the method is not static or we allow static methods
24262472 if !is_static_method ( item) || render_static {
2427- try!( write ! ( w, "<h4 id='method.{}' class='{}'><code>" ,
2428- * item. name. as_ref( ) . unwrap( ) ,
2429- shortty( item) ) ) ;
2473+ let id = derive_id ( format ! ( "method.{}" , name) ) ;
2474+ try!( write ! ( w, "<h4 id='{}' class='{}'><code>" , id, shortty( item) ) ) ;
24302475 try!( render_assoc_item ( w, item, link) ) ;
24312476 try!( write ! ( w, "</code></h4>\n " ) ) ;
24322477 }
24332478 }
24342479 clean:: TypedefItem ( ref tydef, _) => {
2435- let name = item. name . as_ref ( ) . unwrap ( ) ;
2436- try!( write ! ( w, "<h4 id='assoc_type.{}' class='{}'><code>" ,
2437- * name,
2438- shortty( item) ) ) ;
2480+ let id = derive_id ( format ! ( "assoc_type.{}" , name) ) ;
2481+ try!( write ! ( w, "<h4 id='{}' class='{}'><code>" , id, shortty( item) ) ) ;
24392482 try!( write ! ( w, "type {} = {}" , name, tydef. type_) ) ;
24402483 try!( write ! ( w, "</code></h4>\n " ) ) ;
24412484 }
24422485 clean:: AssociatedConstItem ( ref ty, ref default) => {
2443- let name = item. name . as_ref ( ) . unwrap ( ) ;
2444- try!( write ! ( w, "<h4 id='assoc_const.{}' class='{}'><code>" ,
2445- * name, shortty( item) ) ) ;
2486+ let id = derive_id ( format ! ( "assoc_const.{}" , name) ) ;
2487+ try!( write ! ( w, "<h4 id='{}' class='{}'><code>" , id, shortty( item) ) ) ;
24462488 try!( assoc_const ( w, item, ty, default. as_ref ( ) ) ) ;
24472489 try!( write ! ( w, "</code></h4>\n " ) ) ;
24482490 }
24492491 clean:: ConstantItem ( ref c) => {
2450- let name = item. name . as_ref ( ) . unwrap ( ) ;
2451- try!( write ! ( w, "<h4 id='assoc_const.{}' class='{}'><code>" ,
2452- * name, shortty( item) ) ) ;
2492+ let id = derive_id ( format ! ( "assoc_const.{}" , name) ) ;
2493+ try!( write ! ( w, "<h4 id='{}' class='{}'><code>" , id, shortty( item) ) ) ;
24532494 try!( assoc_const ( w, item, & c. type_ , Some ( & c. expr ) ) ) ;
24542495 try!( write ! ( w, "</code></h4>\n " ) ) ;
24552496 }
24562497 clean:: AssociatedTypeItem ( ref bounds, ref default) => {
2457- let name = item. name . as_ref ( ) . unwrap ( ) ;
2458- try!( write ! ( w, "<h4 id='assoc_type.{}' class='{}'><code>" ,
2459- * name,
2460- shortty( item) ) ) ;
2498+ let id = derive_id ( format ! ( "assoc_type.{}" , name) ) ;
2499+ try!( write ! ( w, "<h4 id='{}' class='{}'><code>" , id, shortty( item) ) ) ;
24612500 try!( assoc_type ( w, item, bounds, default) ) ;
24622501 try!( write ! ( w, "</code></h4>\n " ) ) ;
24632502 }
@@ -2671,3 +2710,22 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<String> {
26712710pub fn cache ( ) -> Arc < Cache > {
26722711 CACHE_KEY . with ( |c| c. borrow ( ) . clone ( ) )
26732712}
2713+
2714+ #[ cfg( test) ]
2715+ #[ test]
2716+ fn test_unique_id ( ) {
2717+ let input = [ "foo" , "examples" , "examples" , "method.into_iter" , "examples" ,
2718+ "method.into_iter" , "foo" , "main" , "search" , "methods" ,
2719+ "examples" , "method.into_iter" , "assoc_type.Item" , "assoc_type.Item" ] ;
2720+ let expected = [ "foo" , "examples" , "examples-1" , "method.into_iter" , "examples-2" ,
2721+ "method.into_iter-1" , "foo-1" , "main-1" , "search-1" , "methods-1" ,
2722+ "examples-3" , "method.into_iter-2" , "assoc_type.Item" , "assoc_type.Item-1" ] ;
2723+
2724+ let test = || {
2725+ let actual: Vec < String > = input. iter ( ) . map ( |s| derive_id ( s. to_string ( ) ) ) . collect ( ) ;
2726+ assert_eq ! ( & actual[ ..] , expected) ;
2727+ } ;
2728+ test ( ) ;
2729+ reset_ids ( ) ;
2730+ test ( ) ;
2731+ }
0 commit comments