Function update_file

Source
pub fn update_file<F, N, E>(
    original: F,
    rebuilt: impl FnOnce() -> Result<N>,
    f: impl FnOnce(&mut BlockList) -> Result<(), E>,
) -> Result<bool, E>
where F: Read + Seek + Write, N: Write, E: From<Error>,
Expand description

Given open file, attempts to update its metadata blocks

The original file should be rewound to the start of the stream.

Applies closure f to the blocks and attempts to update them.

If the updated blocks can be made the same size as the original file by adjusting padding, the file will be partially overwritten with new contents.

If the new blocks are too large (or small) to fit into the original file, the original unmodified file is dropped and the rebuilt closure is called to build a new file. The file’s contents are then dumped into the new file.

Returns true if the file was completely rebuilt, or false if the original was overwritten.

§Example 1

use flac_codec::{
    metadata::{update_file, BlockList, Padding, VorbisComment},
    metadata::fields::TITLE,
    encode::{FlacSampleWriter, Options},
};
use std::io::{Cursor, Seek};

let mut flac = Cursor::new(vec![]);  // a FLAC file in memory

// include a small amount of padding
const PADDING_SIZE: u32 = 100;
let options = Options::default().padding(PADDING_SIZE).unwrap();

let mut writer = FlacSampleWriter::new(
    &mut flac,  // our wrapped writer
    options,    // our encoding options
    44100,      // sample rate
    16,         // bits-per-sample
    1,          // channel count
    Some(1),    // total samples
).unwrap();

// write a simple FLAC file
writer.write(std::slice::from_ref(&0)).unwrap();
writer.finalize().unwrap();

flac.rewind().unwrap();

let mut rebuilt: Vec<u8> = vec![];

// update file with new Vorbis Comment
assert!(matches!(
    update_file::<_, _, flac_codec::Error>(
        // our original file
        &mut flac,
        // a closure to create a new file, if necessary
        || Ok(&mut rebuilt),
        // the closure that performs the metadata update
        |blocklist| {
            blocklist.update::<VorbisComment>(
                // the blocklist itself has a closure
                // that updates a block, creating it if necessary
                // (in this case, we're updating the Vorbis comment)
                |vc| vc.set(TITLE, "Track Title")
            );
            Ok(())
        },
    ),
    Ok(false),  // false indicates the original file was updated
));

flac.rewind().unwrap();

// re-read the metadata blocks from the original file
let blocks = BlockList::read(flac).unwrap();

// the original file now has a Vorbis Comment block
// with the track title that we added
assert_eq!(
    blocks.get::<VorbisComment>().and_then(|vc| vc.get(TITLE)),
    Some("Track Title"),
);

// the original file's padding block is smaller than before
// to accomodate our new Vorbis Comment block
assert!(u32::from(blocks.get::<Padding>().unwrap().size) < PADDING_SIZE);

// and the unneeded rebuilt file remains empty
assert!(rebuilt.is_empty());

§Example 2

use flac_codec::{
    metadata::{update_file, BlockList, VorbisComment},
    metadata::fields::TITLE,
    encode::{FlacSampleWriter, Options},
};
use std::io::{Cursor, Seek};

let mut flac = Cursor::new(vec![]);  // a FLAC file in memory

// include no padding in our encoded file
let options = Options::default().no_padding();

let mut writer = FlacSampleWriter::new(
    &mut flac,  // our wrapped writer
    options,    // our encoding options
    44100,      // sample rate
    16,         // bits-per-sample
    1,          // channel count
    Some(1),    // total samples
).unwrap();

// write a simple FLAC file
writer.write(std::slice::from_ref(&0)).unwrap();
writer.finalize().unwrap();

flac.rewind().unwrap();

let mut rebuilt: Vec<u8> = vec![];

// update file with new Vorbis Comment
assert!(matches!(
    update_file::<_, _, flac_codec::Error>(
        // our original file
        &mut flac,
        // a closure to create a new file, if necessary
        || Ok(&mut rebuilt),
        // the closure that performs the metadata update
        |blocklist| {
            blocklist.update::<VorbisComment>(
                // the blocklist itself has a closure
                // that updates a block, creating it if necessary
                // (in this case, we're updating the Vorbis comment)
                |vc| vc.set(TITLE, "Track Title")
            );
            Ok(())
        },
    ),
    Ok(true),  // true indicates the original file was not updated
));

flac.rewind().unwrap();

// re-read the metadata blocks from the original file
let blocks = BlockList::read(flac).unwrap();

// the original file remains unchanged
// and has no Vorbis Comment block
assert_eq!(blocks.get::<VorbisComment>(), None);

// now read the metadata blocks from the rebuilt file
let blocks = BlockList::read(rebuilt.as_slice()).unwrap();

// the rebuilt file has our Vorbis Comment entry instead
assert_eq!(
    blocks.get::<VorbisComment>().and_then(|vc| vc.get(TITLE)),
    Some("Track Title"),
);