You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: column_operation.rs
    path of file: ./repos/tantivy/columnar/src/columnar/writer
    
    the code of the file until where you have to start completion: use std::net::Ipv6Addr;

use crate::dictionary::UnorderedId;
use crate::utils::{place_bits, pop_first_byte, select_bits};
use crate::value::NumericalValue;
use crate::{InvalidData, NumericalType, RowId};

/// When we build a columnar dataframe, we first just group
/// all mutations per column, and appends them in append-only buffer
/// in the stacker.
///
/// These ColumnOperation<T> are therefore serialize/deserialized
/// in memory.
///
/// We represents all of these operations as `ColumnOperation`.
#[derive(Eq, PartialEq, De
    
    fn serialize(self, output: &mut [u8]) -> u8 {
        match self {
            NumericalValue::F64(val) => {
                output[0] = NumericalType::F64 as u8;
                output[1..9].copy_from_slice(&val.to_le_bytes());
                9u8
            }
            NumericalValue::U64(val) => {
                let len = compute_num_bytes_for_u64(val) as u8;
                output[0] = NumericalType::U64 as u8;
                output[1..9].copy_from_slice(&val.to_le_bytes());
                len + 1u8
            }
            NumericalValue::I64(val) => {
                let zig_zag_encoded = encode_zig_zag(val);
                let len = compute_num_bytes_for_u64(zig_zag_encoded) as u8;
                output[0] = NumericalType::I64 as u8;
                output[1..9].copy_from_slice(&zig_zag_encoded.to_le_bytes());
                len + 1u8
            }
        }
    }