11//! Various utilities.
22
3- use crate :: ALIGNMENT ;
3+ use crate :: tag:: GenericTag ;
4+ use crate :: { TagHeader , TagTrait , TagType , ALIGNMENT } ;
45use core:: fmt;
56use core:: fmt:: { Display , Formatter } ;
67use core:: str:: Utf8Error ;
8+ use core:: { ptr, slice} ;
9+ #[ cfg( feature = "builder" ) ]
10+ use { alloc:: alloc:: Layout , alloc:: boxed:: Box } ;
711
812/// Error type describing failures when parsing the string from a tag.
913#[ derive( Debug , PartialEq , Eq , Clone ) ]
@@ -31,6 +35,38 @@ impl core::error::Error for StringError {
3135 }
3236}
3337
38+ /// Creates a new tag implementing [`TagTrait`] on the heap. This works for
39+ /// sized and unsized tags. However, it only makes sense to use this for tags
40+ /// that are DSTs (unsized), as for the sized ones, you can call a regular
41+ /// constructor and box the result.
42+ ///
43+ /// # Parameters
44+ /// - `additional_bytes`: All bytes apart from the default [`TagHeader`] that
45+ /// are included into the tag.
46+ #[ cfg( feature = "alloc" ) ]
47+ pub fn new_boxed < T : TagTrait + ?Sized > ( additional_bytes : & [ u8 ] ) -> Box < T > {
48+ let size = size_of :: < TagHeader > ( ) + additional_bytes. iter ( ) . len ( ) ;
49+ let alloc_size = increase_to_alignment ( size) ;
50+ let layout = Layout :: from_size_align ( alloc_size, ALIGNMENT ) . unwrap ( ) ;
51+ let heap_ptr = unsafe { alloc:: alloc:: alloc ( layout) } ;
52+ assert ! ( !heap_ptr. is_null( ) ) ;
53+
54+ unsafe {
55+ heap_ptr. cast :: < u32 > ( ) . write ( T :: ID . val ( ) ) ;
56+ heap_ptr. cast :: < u32 > ( ) . add ( 1 ) . write ( size as u32 ) ;
57+ }
58+ unsafe {
59+ let ptr = heap_ptr. add ( size_of :: < TagHeader > ( ) ) ;
60+ ptr:: copy_nonoverlapping ( additional_bytes. as_ptr ( ) , ptr, additional_bytes. len ( ) ) ;
61+ }
62+
63+ let header = unsafe { heap_ptr. cast :: < TagHeader > ( ) . as_ref ( ) } . unwrap ( ) ;
64+
65+ let ptr = ptr_meta:: from_raw_parts_mut ( heap_ptr. cast ( ) , T :: dst_len ( header) ) ;
66+
67+ unsafe { Box :: from_raw ( ptr) }
68+ }
69+
3470/// Parses the provided byte sequence as Multiboot string, which maps to a
3571/// [`str`].
3672pub fn parse_slice_as_string ( bytes : & [ u8 ] ) -> Result < & str , StringError > {
@@ -52,6 +88,8 @@ pub const fn increase_to_alignment(size: usize) -> usize {
5288#[ cfg( test) ]
5389mod tests {
5490 use super :: * ;
91+ use crate :: tag:: GenericTag ;
92+ use crate :: CommandLineTag ;
5593
5694 #[ test]
5795 fn test_parse_slice_as_string ( ) {
@@ -87,4 +125,13 @@ mod tests {
87125 assert_eq ! ( increase_to_alignment( 8 ) , 8 ) ;
88126 assert_eq ! ( increase_to_alignment( 9 ) , 16 ) ;
89127 }
128+
129+ #[ test]
130+ fn test_new_boxed ( ) {
131+ let tag = new_boxed :: < GenericTag > ( & [ 0 , 1 , 2 , 3 ] ) ;
132+ assert_eq ! ( tag. header( ) . typ, GenericTag :: ID ) ;
133+ { }
134+ let tag = new_boxed :: < CommandLineTag > ( "hello\0 " . as_bytes ( ) ) ;
135+ assert_eq ! ( tag. cmdline( ) , Ok ( "hello" ) ) ;
136+ }
90137}
0 commit comments